DMARC

DMARC

Note

If you are reviewing old records, you might see a DKIM record with v=DKIM1; o=~. This is an outdated and unused spec; it can be deleted without issue.[2] [3]

DMARC Implementation

Warning

Both SPF and DKIM must be configured before setting the DMARC policy to quarantine or reject. Failure to do so will result in undelivered mail.

Configuring DMARC is easy, but can cause you the most headaches because it's what authorizes email to be delivered, and a misconfiguration can stop your email in its tracks. Therefore, it's highly recommended that you first configure your DMARC policy to none to take no action on emails for the first couple of weeks, using the reports generated to make sure everything is getting delivered as expected, and then to add a quarantine or reject policy and maybe ramp up implementation through the pct tag.

Below is an example of a DMARC TXT record:

  1. Name: _dmarc
  2. Type: TXT
  3. TTL: 3600
  4. Value: v=DMARC1; p=quarantine; sp=reject; pct=100; aspf=r; adkim=r; rua=mailto:dmarc-reports@example.com; ruf=mailto:dmarc-failures@example.com; fo=1; ri=43200

Let's break it down.

  1. Name: _dmarc.example.com
    1. _dmarc
      1. Signifies this a DMARC TXT entry
    2. Note that you do not typically need to enter the root domain here; however, if you did a DMARC lookup for example.com, you would see the entry as _dmarc.example.com
      1. Only one DMARC record needs to exist for the apex domain, but you can add more records for different subdomains to take different actions; for example, _dmarc.mailer.example.com
  2. Type: TXT
    1. This is a text record (as opposed to A, CNAME, etc.)
  3. TTL: 3600
    1. The time to live is 1 hour (3600 seconds)
    2. This is an expiration date for the DMARC record, and helps DNS servers maintain up-to-date records.
  4. Value: v=DMARC1; p=quarantine; sp=reject; pct=100; aspf=r; adkim=r; rua=mailto:dmarc-reports@example.com; ruf=mailto:dmarc-failures@example.com; fo=1;
    1. v=DMARC1
      1. DMARC version 1; at present, there is only one version.
    2. ;
      1. The separator between tags.
      2. Spaces and tabs can make entries more readable, but are completely optional.
    3. p=quarantine
      1. The Policy applied to emails which fail their SPF and DKIM authentication checks
      2. There are three options:
        1. none: No action is taken
          1. Typically used while configuring email security and collecting reports.
        2. quarantine: Emails which fail authentication should be treated with suspicion and sent to the spam/junk folder
          1. This allows the recipient server to still receive and process unauthenticated mail, just treats them with suspicion
        3. reject: Instructs the receiving server to outright reject any mail that fails authentication.
          1. This is the most secure, but can also be the most problematic if a configuration changes or something goes wrong.
    4. sp=reject
      1. The policy for subdomains; if sp is not stated in the record, then the policy described by p is inherited by its subdomains.
        1. Setting sp may be helpful to set a stricter policy if there are no subdomains, or a looser policy if configuring a subdomain for mail.
        2. Some receiving servers don't check the root domain for a DMARC policy to inherit; playing it safe and adding a DMARC record for your subdomains is not a bad idea.
      2. Creating a distinct DMARC policy for a subdomain (e.g., _dmarc.mailer.example.com) takes precedence over the sp policy designation.
        1. To reiterate, sp only applies to a subdomain if there isn't a more specific DMARC policy created for it.
    5. pct=100
      1. The percent of unauthenticated emails to apply the policy to.
        1. e.g., pct=20 would only apply the p=reject policy to 20% of emails which fail authentication
      2. This is helpful during a slow rollout to make sure not all email flow stops.
      3. Default is 100, and does not need to be explicitly written.
    6. aspf=r
      1. SPF alignment requirements
        1. r is relaxed, and only the root/organizational domain must match
          1. Relaxed is the default value for both aspf and adkim, and does not need to be explicitly stated
        2. s is strict, and domains must match exactly
    7. adkim=r
      1. DKIM alignment requirements; see aspf for details.
    8. rua=mailto:dmarc-reports@example.com
      1. Identifies the email address to which recipient servers should send delivery aggregate reports
      2. Each address must begin with mailto:, and multiple addresses can be specified if separated by a comma.
        1. e.g., rua=mailto:address1@example.com,mailto:address2@contoso.com
      3. Aggregate reports contain basic information and include successful and failed delivery information
    9. ruf=mailto:dmarc-failures@example.com
      1. Identifies the email address to which recipient servers should send individual delivery forensic failure reports
      2. Forensic failure reports contain detailed information about failed deliveries to assist with triage and troubleshooting.
        1. However, most major providers highly redact or suppress ruf records for privacy and GDPR compliance.
    10. fo=1
      1. The failure reporting option specifies what generates a forensic report .
        1. 0 is default, and only requests forensic reports on DMARC failure.
        2. 1 requests a report for any SPF or DKIM failure, which is helpful for triage and troubleshooting during initial setup.
        3. d generates a report only when DKIM authentication (not alignment)
        4. s generates a report when SPF fails.
      2. You can select multiple options with a colon (e.g., fo=0:d)
      3. Reminder: many mailbox providers don't send forensic/failure reports for GDPR compliance.
    11. ri=43200
      1. The "report interval" is the time in seconds you request receivers to generate reports.
        1. The default is 24 hours (86400 seconds), and 12 hours as configured here.
      2. Most providers ignore this, and send reports every 24 hours or more based on their own infrastructure.
        1. "DMARC implementations MUST be able to provide daily reports and SHOULD be able to provide hourly reports when requested. However, anything other than a daily report is understood to be accommodated on a best-effort basis."[4]
Sending Reports to a Different Domain

If you are sending DMARC reports to another domain for analysis, you will need to create a TXT record on that domain's name server to identify each sending domain.[5]

For example:

  1. Type: TXT
  2. Name: sendingdomain.com._report._dmarc.receivingdomain.com
    1. For example, if the MSP AcmeIT.com was configured to receive and manage DMARC reports for example.com, the record would be example.com._report._dmarc.acmeit.com
  3. Value: "v=DMARC1"
    1. Just indicates the version of DMARC

The TXT record name identifies the domain generating the report (sendingdomain.com), followed by ._report._dmarc and the domain receiving the reports (.receivingdomain.com).
The TXT record value just identifies the DMARC version ("v=DMARC1")

Warning

While you can use a * wildcard to simplify the record to *._report._dmarc.receivingdomain.com, allowing anyone to send email to your DMARC report inboxes, you probably shouldn't. Spam filters and firewalls don't typically inspect DMARC reports, and an attacker could exploit this to flood the inbox with bogus DMARC reports or inject malicious code into zipped attachments, which might get run automatically by report analyzing software.

dig

Using dig to verify SPF, DKIM, and DMARC

When using dig to verify records and look up changes, only SPF can be searched generally; DKIM and DMARC searches must include the full name of the record.

In the examples, I rotated the DNS server I was querying to demonstrate that any DNS server could be used. Records for subdomains or named records above root (e.g., mail.example.com or _dmarc.example.com) will require their own dig queries.

  1. SPF
    1. dig @8.8.8.8 example.com TXT +noall +answer
      1. This will return all root TXT records, so you may get several irrelevant responses in addition to the SPF
  2. DKIM
    1. dig @1.1.1.1 mx01._domainkey.example.com TXT +noall +answer
      1. Returns the final DKIM record value, whether stored on your name server or redirected via a CNAME
    2. dig @1.0.0.1 protonmail._domainkey.example.com CNAME +noall +answer
      1. Only returns the CNAME record on your server, if applicable.
  3. DMARC
    1. dig @8.8.4.4 _dmarc.example.com TXT +noall +answer
      1. This will return the DMARC record for example.com
    2. dig @1.1.1.1 _dmarc.mail.example.com txt +noall +answer
      1. Returns the DMARC record for the subdomain mail.example.com

If the record exists and you entered the command correctly, you should get responses with all the information in the record being queried.

Metadata

Sources

RFC 7489 - Domain-based Message Authentication, Reporting, and Conformance (DMARC)
dmarc.org – Domain Message Authentication Reporting & Conformance
DMARC - Wikipedia
Learn and Test DMARC
Use DMARC to validate email, setup steps - Microsoft Defender for Office 365 | Microsoft Learn
The DMARC ‘fo’ tag options and their ideal use cases – DMARC Report

Tools

DMARC Report Analyzer
GitHub - techsneeze/dmarcts-report-parser: A Perl based tool to parse DMARC reports from an IMAP mailbox or from the filesystem, and insert the information into a database. ( Formerly known as imap-dmarcts )

Tags

#defs_sec


  1. This review offers a few others: Free DMARC Monitoring Tools: We Test Out 7 Options ↩︎

  2. What is this extra _domainkey.? Should I kill it? : r/DMARC ↩︎

  3. draft-allman-dkim-ssp-01 ↩︎

  4. RFC 7489 - Domain-based Message Authentication, Reporting, and Conformance (DMARC) ↩︎

  5. DMARC - DMARC External Validation ↩︎