Aggregate reports are what make DMARC deployable. They are also XML, delivered by email, in a gzip attachment — which is why most people never look at one directly. Reading one by hand once is worth doing, because every dashboard you use afterwards is a rendering of this structure and its limitations are the structure’s limitations.
The shape of a report
One report covers one domain, from one receiver, over one period — usually 24 hours. It has a metadata block, a copy of the policy that was applied, and then a set of rows.
<feedback>
<report_metadata>
<org_name>google.com</org_name>
<report_id>1234567890123456789</report_id>
<date_range><begin>1757548800</begin><end>1757635200</end></date_range>
</report_metadata>
<policy_published>
<domain>example.com</domain>
<adkim>r</adkim> <aspf>r</aspf>
<p>none</p> <sp>none</sp> <pct>100</pct>
</policy_published>
<record>
<row>
<source_ip>198.51.100.25</source_ip>
<count>412</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>sel1</selector><result>pass</result></dkim>
<spf><domain>mail.vendor.example</domain><result>pass</result></spf>
</auth_results>
</record>
</feedback>What one record means
A record is not one message. It is every message this receiver saw, in this period, from this source IP, that produced this combination of results — the count says how many.
So 412 messages from 198.51.100.25, all with the same outcome, collapse into one block. Change any one result and it becomes a separate block.
The two places results appear, and why they differ
This is the part that confuses people, and it is the most useful thing in the report.
| Element | Reports |
|---|---|
auth_results | The raw result of each check, and the domain it was for. SPF passed here — for mail.vendor.example. |
policy_evaluated | The result after alignment. SPF is fail here, because the domain it passed for is not aligned with example.com. |
How to spot an alignment problem in one glance
auth_results says pass, policy_evaluated says fail. The check worked; the domain was wrong. Every alignment failure in your estate looks exactly like that, and the domain named in auth_results tells you which sender to go and fix.
In the example above, DKIM saves the message: it passed for example.com, which is aligned, so policy_evaluated shows dkim=pass and the overall DMARC result is a pass despite SPF being unaligned.
disposition is what happened, not what you asked for
policy_evaluated/disposition records what the receiver actually did. It is usually the same as your published policy and it does not have to be — RFC 7489 §6.7 lets receivers deviate. Watching disposition diverge from your policy is how you learn a receiver is applying local overrides, and that is information you only get here.
What reports do not contain
- Message content. Never. No subjects, no bodies, no recipient addresses. That is a privacy property of the format, not an omission.
- Individual messages. Only counts by source and result.
- Mail that was never sent. Reports tell you about traffic claiming your domain. Absence of a sender from a report means nobody saw it, not that it does not exist.
Doing it once by hand
Take one report from your own rua mailbox and open it:
gunzip -c report.xml.gz | xmllint --format - | less
Then, for each record: read the source IP, read auth_results to see what passed and for which domain, read policy_evaluated to see whether alignment survived, and note the count. Ten minutes on one real report will teach you more about your own mail estate than a week of reading about DMARC.
If no reports are arriving at all despite a correct-looking rua, the cause is very often external destination authorisation, which has its own reference article linked below.