How to read DMARC aggregate reports

A DMARC aggregate report is an XML file that a receiving mail system sends, usually once a day, to the address in the rua tag of your DMARC record. It lists every IP address that sent mail with your domain in the From: header during the period, how many messages each sent, and whether SPF and DKIM passed and aligned with your domain. It contains no message content. Read it to find the services you forgot to authenticate before you tighten your policy, and to spot forgeries of your domain.

Where the format is defined

Aggregate reports were first specified in RFC 7489, section 7.2, with the XML schema in Appendix C. In May 2026 the IETF replaced RFC 7489 with three documents: RFC 9989 for DMARC itself, RFC 9990 for aggregate reporting and RFC 9991 for failure reports. The structure is the same in both versions. Reports built to RFC 9990 use the XML namespace urn:ietf:params:xml:ns:dmarc-2.0 and can carry the new np, testing and discovery_method elements; reports built to RFC 7489's schema can carry pct. A parser should accept both.

Who sends them and how they arrive

A receiver that supports DMARC finds your reporting request when it looks up your DMARC record for incoming mail. Without a rua tag it must not send aggregate reports at all (RFC 9989, section 4.7). You can list several addresses, separated by commas, and a report should go to each. Yahoo's sender best practices strongly recommend a rua address for bulk senders; see Gmail and Yahoo sender requirements.

RFC 9990, section 3.5.2, fixes the email format:

A report covers one DMARC policy domain. Subdomains without their own _dmarc record appear as separate record entries in the report for the parent domain; a subdomain with its own record gets its own report (RFC 9990, section 3.1.2).

Expect volume. Google's About DMARC reports says large organizations can receive hundreds or even thousands of reports a day, and recommends a dedicated group or mailbox for them. RFC 9989 recommends parsing reports by machine rather than reading them by hand.

The main elements

ElementWhat it holds
report_metadataWho sent the report (org_name, email), a unique report_id, the date_range (begin, end) and any error found in your record
policy_publishedYour record as the receiver saw it: domain, p, sp, alignment modes adkim and aspf, and newer or older tags
recordOne per combination of sending IP, results and identifiers; a report has at least one
rowsource_ip, the message count, and policy_evaluated
policy_evaluatedThe disposition applied (none, quarantine, reject, or pass in RFC 9990) and the DMARC verdicts for dkim and spf, plus an optional reason
identifiersheader_from (the From: domain), and optionally envelope_from and envelope_to
auth_resultsRaw results: each dkim signature with domain, selector and result, and the spf check with domain and result

The date_range marks the reporting period, not the first and last message, and RFC 9990 says it typically covers one UTC day starting at 00:00.

An annotated example

A shortened report for example.com, with documentation IP addresses:

<feedback xmlns="urn:ietf:params:xml:ns:dmarc-2.0">
  <report_metadata>
    <org_name>receiver.example</org_name>
    <email>dmarc-reports@receiver.example</email>
    <report_id>2026-11-05_example.com@receiver.example</report_id>
    <date_range><begin>1793836800</begin><end>1793923199</end></date_range>
  </report_metadata>
  <policy_published>
    <domain>example.com</domain>
    <p>none</p><sp>none</sp><adkim>r</adkim><aspf>r</aspf>
  </policy_published>
  <record>                                   <!-- 1: your own mail, fully aligned -->
    <row>
      <source_ip>192.0.2.25</source_ip><count>1840</count>
      <policy_evaluated><disposition>none</disposition><dkim>pass</dkim><spf>pass</spf></policy_evaluated>
    </row>
    <identifiers><header_from>example.com</header_from></identifiers>
    <auth_results>
      <dkim><domain>example.com</domain><selector>s1</selector><result>pass</result></dkim>
      <spf><domain>bounce.example.com</domain><result>pass</result></spf>
    </auth_results>
  </record>
  <record>                                   <!-- 2: a platform signing with its own domain -->
    <row>
      <source_ip>198.51.100.7</source_ip><count>312</count>
      <policy_evaluated><disposition>none</disposition><dkim>fail</dkim><spf>fail</spf></policy_evaluated>
    </row>
    <identifiers><header_from>example.com</header_from></identifiers>
    <auth_results>
      <dkim><domain>platform.example</domain><selector>k1</selector><result>pass</result></dkim>
      <spf><domain>mail.platform.example</domain><result>pass</result></spf>
    </auth_results>
  </record>
  <record>                                   <!-- 3: forwarded copies -->
    <row>
      <source_ip>203.0.113.40</source_ip><count>6</count>
      <policy_evaluated><disposition>none</disposition><dkim>pass</dkim><spf>fail</spf></policy_evaluated>
    </row>
    <identifiers><header_from>example.com</header_from></identifiers>
    <auth_results>
      <dkim><domain>example.com</domain><selector>s1</selector><result>pass</result></dkim>
      <spf><domain>example.com</domain><result>fail</result></spf>
    </auth_results>
  </record>
</feedback>

The period is 5 November 2026, 00:00 to 23:59:59 UTC. The receiver saw p=none, so nothing was quarantined or rejected, whatever the results.

How to read pass, fail and alignment

The key is the difference between the two blocks. auth_results holds the plain SPF and DKIM results, before DMARC looks at alignment. policy_evaluated holds the DMARC verdicts: pass only if the check passed for a domain that aligns with header_from (RFC 9990, section 3.1.1). DMARC passes if either verdict is pass.

auth_resultspolicy_evaluatedLikely meaning
DKIM and SPF pass for your domainpass / passCorrectly set up
Pass, but for another domainfail / failA service you use without alignment
DKIM passes for you, SPF failspass / failForwarding; DMARC still passes
DKIM fails, SPF fails or another domainfail / failA mailing list that changed the message, or a broken signature
No DKIM, SPF fails, unknown IPfail / failPossible forgery, or a sender nobody told you about

To identify a source IP, look up its PTR name (see reverse DNS) and compare it with the services your company uses. The DKIM selector often points to the service too; see DKIM selectors and key rotation. Look at counts: a few messages from an unknown IP matter less than a steady stream.

Forwarding and mailing list noise

Forwarders send your mail on from their own IP addresses, so SPF fails for those copies, while DKIM usually survives. Mailing lists that add a subject tag or footer break DKIM as well (RFC 7960, sections 2.2 and 3.2.3). Such rows will appear in your reports with small counts from IP addresses you have never heard of. Do not add those IPs to your SPF record: they are not yours, and aligned DKIM is the fix that carries through forwarding.

When a receiver applies something other than your policy, it can say why in policy_evaluated/reason. RFC 9990, section 3.1.6, defines the types local_policy, mailing_list, trusted_forwarder, policy_test_mode (your record has t=y) and other; RFC 7489 also had forwarded and sampled_out (excluded by pct). Google's report page mentions accepting unauthenticated mail because it passed ARC as one such action.

Sending reports to another domain

If the rua address is in a different organizational domain from your record, for example a report-processing service, the receiver first checks that the destination agrees to take your reports (RFC 7489, section 7.1; RFC 9990, section 4). It looks for a TXT record named after your domain under _report._dmarc at the destination:

_dmarc.example.com.                          TXT  "v=DMARC1; p=none; rua=mailto:dmarc@reports.example.net"
example.com._report._dmarc.reports.example.net.  TXT  "v=DMARC1"

The second record is published by the owner of reports.example.net. Without it, receivers ignore that address. A destination willing to accept reports for any domain can publish a wildcard, *._report._dmarc.reports.example.net. If you send reports to an address within your own organizational domain, no extra record is needed.

Failure reports (ruf)

The ruf tag requests failure reports: one report per failing message, or per group of similar ones, sent soon after the failure and carrying the message's header fields or even its full content (RFC 9991, sections 1 and 2). The fo tag chooses when they are sent.

Expect few of them. Google's Set up DMARC page says Gmail does not support ruf, and RFC 9991, section 7, notes that many large providers limit or disable failure reports because of privacy concerns. Aggregate reports are the dependable source.

Privacy

Aggregate reports contain domain-level data: sending IP addresses, counts and authentication results. RFC 9990, section 7.2, says they do not include individual email addresses or message content. Failure reports are different: they may contain personal data from the message, and RFC 9991 recommends limiting their use to targeted diagnosis and redacting content. If a third party processes your reports, it sees which services send your mail and how much; RFC 9990, section 7.1, asks both domain owners and receivers to check whether their own policies permit that.

Questions

How soon do reports arrive after I publish a rua address?

Reports usually cover a full UTC day and are sent after it ends, so the first ones arrive after the first full day with the record in place. Only receivers that support DMARC reporting and received your mail send one.

Why do the counts not match what I sent?

Each receiver reports only the mail it received, and only receivers that send reports appear. Forwarded copies add rows. Treat totals as a sample of your traffic, not an exact count.

Do I need a paid service to read them?

No. RFC 9989, section 5.1.5, mentions both third-party services and your own tools; the XML is documented, so a small domain can parse it with a script. Google suggests a service that specializes in DMARC, since it combines and analyzes reports from many receivers.

Try it

Check whether your record has a valid rua address with the DMARC checker, or write one with the DMARC generator.

Sources

How we wrote this: drafted by the email-validation.org team with the help of AI writing tools, from our product documentation and the sources linked in the text.

Get up to 500 free credits. No card needed.

New accounts get 500 free credits (100 when you sign up with a free email provider such as Gmail, Outlook or Yahoo, or another personal mailbox such as a paid one like Fastmail or one from your internet provider). Try it on your own list before you buy.

Updated · Maintained by the email-validation.org team