Where RUA Reports Come From {#where-reports-come-from}
RUA reports are generated by any receiving mail server that checks DMARC on inbound mail — Gmail, Microsoft 365/Outlook, Yahoo, and most enterprise mail gateways. They're sent to the address in the rua= tag of your DMARC TXT record, defined in RFC 7489 §6.3:
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@example.com"
Each provider reports independently, so if your domain sends to Gmail, Outlook, and Yahoo recipients, expect at least three separate .xml.gz files per day — one per reporting organization. Per RFC 7489 §7.2, the default reporting interval (ri tag) is 86400 seconds (24 hours), and compliant receivers must support at least daily reporting even if you request a shorter interval.
The files arrive gzip-compressed with names like google.com!example.com!1735689600!1735776000.xml.gz — the two numbers before the extension are Unix epoch timestamps marking the start and end of the report's 24-hour window; decode them to confirm you're looking at the right day before drawing conclusions from the data. Once you're receiving reports from more than two or three providers a day, reading each file by hand stops scaling — run them through the DMARC Report Analyzer instead, which aggregates every report into one table of source IPs, pass/fail counts, and disposition across your full reporting history rather than one file at a time.
The XML Structure, Section by Section {#xml-structure}
Per RFC 7489 Appendix C, every RUA file has this shape:
<feedback>
<report_metadata>
<org_name>google.com</org_name>
<email>noreply-dmarc-support@google.com</email>
<report_id>10123456789012345678</report_id>
<date_range>
<begin>1735689600</begin>
<end>1735776000</end>
</date_range>
</report_metadata>
<policy_published>
<domain>example.com</domain>
<p>quarantine</p>
<sp>quarantine</sp>
<pct>100</pct>
<aspf>r</aspf>
<adkim>r</adkim>
</policy_published>
<record>
<row>
<source_ip>203.0.113.45</source_ip>
<count>842</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>
<spf>
<domain>example.com</domain>
<result>pass</result>
</spf>
<dkim>
<domain>example.com</domain>
<result>pass</result>
<selector>google</selector>
</dkim>
</auth_results>
</record>
</feedback>
report_metadata tells you who sent the report and the exact 24-hour window it covers. policy_published is a snapshot of the DMARC record the receiver saw at evaluation time — useful for confirming your record propagated correctly; cross-check it against a live lookup with the DMARC Checker. Everything after that is one <record> block per unique sending IP.
Reference Table: Every Field Explained {#reference-table}
| Field | Location | Meaning |
|---|---|---|
org_name | report_metadata | The mailbox provider that generated the report (e.g., google.com) |
date_range | report_metadata | Unix timestamps for the 24-hour window covered |
p / sp | policy_published | Enforcement policy for the domain / subdomains: none, quarantine, reject |
pct | policy_published | Percentage of failing mail the policy applies to (100 = full enforcement) |
source_ip | row | The IP address that sent the message |
count | row | Number of messages from that IP in this window |
disposition | policy_evaluated | Action actually taken: none, quarantine, or reject |
dkim / spf (in policy_evaluated) | policy_evaluated | Alignment result — pass only if the domain matches the From header per DMARC's relaxed/strict mode |
header_from | identifiers | The visible From domain recipients saw |
auth_results > spf > result | auth_results | Raw SPF check result, independent of alignment |
auth_results > dkim > result | auth_results | Raw DKIM signature validity, independent of alignment |
A record can show spf result=pass in auth_results yet still fail DMARC — that gap means SPF passed for a different domain (e.g., a third-party sender) that never aligned with your From header.
Reading a Real Record {#reading-a-real-record}
The most common confusion is treating auth_results and policy_evaluated as the same thing. They're not:
auth_resultsis the raw protocol check — did SPF/DKIM pass at all, for any domain.policy_evaluatedis the DMARC-specific result — did that pass also align with your visible From domain.
Take this record:
<row>
<source_ip>198.51.100.9</source_ip>
<count>15</count>
<policy_evaluated>
<disposition>quarantine</disposition>
<dkim>fail</dkim>
<spf>fail</spf>
</policy_evaluated>
</row>
<auth_results>
<spf>
<domain>mailer3.thirdpartyapp.com</domain>
<result>pass</result>
</spf>
</auth_results>
SPF passed for mailer3.thirdpartyapp.com, but the header From was example.com — no alignment, so policy_evaluated > spf shows fail and the message was quarantined. This is the classic signature of a marketing or transactional email platform sending on your behalf without SPF/DKIM alignment configured. The fix is either adding that platform's include to your SPF record with the SPF Checker or configuring DKIM signing through the platform so it aligns.
Common Issues You'll Find in RUA Data {#common-issues}
Legitimate senders failing alignment. Marketing tools, CRMs, and helpdesk platforms often send as your domain without matching SPF/DKIM. Cross-reference every failing source_ip against your known sending services before assuming it's spoofing.
Unauthorized IPs with high volume. A source IP you don't recognize sending hundreds of messages a day, failing both SPF and DKIM, is the strongest signal of domain spoofing — the exact case DMARC exists to catch.
Disposition stuck at none despite a stricter policy. If your record specifies p=quarantine but every record shows disposition=none, check pct in policy_published — a pct below 100 tells receivers to apply the policy to only a percentage of failing mail, common during gradual rollout.
Report volume dropping suddenly. A missing report from a major provider (no google.com file for several days) usually means the rua= mailbox is bouncing or over its size limit, not that DMARC stopped being checked.
Once you've confirmed which senders are legitimate, use the failure data to plan enforcement — see the full walkthrough in DMARC Explained: p=none vs p=quarantine vs p=reject before moving off p=none.
Decoding RUA Files From the Command Line {#decoding-cli}
Before any parsing tool can help, the attachment needs to be unzipped and formatted. Most providers send .gz, a few send .zip.
# Gmail/most providers: gzip-compressed XML
gunzip google.com!example.com!1735689600!1735776000.xml.gz
# Microsoft/some enterprise senders: zip-compressed XML
unzip outlook.com!example.com!1735689600!1735776000.zip
# Pretty-print the raw XML for manual reading
xmllint --format google.com!example.com!1735689600!1735776000.xml
To pull just the failing records — the ones worth investigating first — filter with xmllint --xpath:
xmllint --xpath "//record[row/policy_evaluated/dkim='fail' or row/policy_evaluated/spf='fail']" \
google.com!example.com!1735689600!1735776000.xml
That returns only <record> blocks where DMARC alignment failed on either mechanism, skipping the (usually much larger) set of passing records from senders already configured correctly. For daily volume beyond a handful of files, this becomes tedious fast — the DMARC Report Analyzer ingests the raw XML directly and gives you the same filtered view without the shell scripting.
Frequently Asked Questions
Q: What's the difference between a DMARC aggregate (RUA) and forensic (RUF) report?
RUA reports are daily XML summaries with counts and pass/fail per source IP — no message content. RUF reports are per-message forensic copies sent in near real time; most providers, including Gmail, no longer send RUF due to privacy concerns.
Q: Why did I get three different reports for the same day?
Each receiving organization (Google, Microsoft, Yahoo) generates its own report independently. A domain sending to all three gets at least one file per provider per reporting window, per RFC 7489 §7.
Q: What does policy_evaluated disposition=none actually mean?
It means no enforcement action was taken on that message regardless of pass/fail — either because your policy is p=none, the pct tag excluded it, or the message passed DMARC outright.
Q: Can I read RUA reports without a paid tool?
Yes — they're plain XML after gunzip. For a handful of reports, opening the file and matching tags against this guide works. Past a few dozen a day, use the DMARC Report Analyzer to aggregate them automatically.
Q: Why does auth_results show spf pass but policy_evaluated shows spf fail?
SPF passed for a domain that doesn't align with your From header — a third-party sender using their own SPF-authorized domain instead of yours. DMARC alignment, not raw SPF/DKIM validity, drives disposition.
Q: How long should I monitor aggregate reports before enforcing p=reject?
Most guidance recommends 2–4 weeks of consistent p=none monitoring with zero unexplained failures before moving to p=quarantine, then another monitoring period before p=reject. Rushing this risks blocking legitimate mail.
Key Takeaways
- ✓ RUA reports contain three sections:
report_metadata,policy_published, and onerecordper sending IP — no message content or PII. - ✓
auth_resultsis the raw SPF/DKIM check;policy_evaluatedis the DMARC alignment result — they can disagree. - ✓
disposition(none/quarantine/reject) is what the receiver actually did with the message. - ✓ Per RFC 7489, expect one independent report per receiving organization, roughly every 24 hours.
- ✓ Cross-check every failing source IP against known senders before treating it as spoofing.
Next Steps
Pull your current DMARC record and confirm what policy receivers are actually evaluating with the DMARC Checker, then feed your raw RUA XML files into the DMARC Report Analyzer to get pass/fail counts per sender without manual parsing. If a legitimate sender is failing alignment, verify its SPF include with the SPF Checker or inspect a specific bounced message with the Email Header Analyzer.