Back to knowledge center
How to Read DMARC Reports: A Field-by-Field Guide to Aggregate XML
security David Lindgren 9 min9/10/2026

How to Read DMARC Reports: A Field-by-Field Guide to Aggregate XML

DMARC aggregate reports look hostile but have only three sections. This guide walks through a real RFC 9990 report field by field, shows the seven row patterns you will actually see, and tells you what to do about each one.

Run the same check right now — free

Enter your domain and get a 9-point audit — DNS, SPF/DKIM/DMARC, SSL, security headers, dark-web exposure — in 60 seconds.

No signup · <60s · GDPR/EU processing

To read a DMARC report, open the compressed XML attachment, look at policy_published to confirm which policy receivers applied, then go through every record block: the source_ip and count tell you who sent how much, policy_evaluated gives the DMARC verdict, and auth_results shows the raw SPF and DKIM results underneath it. A row that passes SPF or DKIM but fails DMARC has an alignment problem. A row that fails everything is either a forgotten sender or someone spoofing you. This guide walks through a real report field by field, shows the seven patterns you will see most often, and explains what to do about each one.

What a DMARC report actually is

Every mail receiver that supports DMARC (Google, Microsoft 365, Yahoo, Mail.ru, Fastmail, Zoho and many others) counts the messages it sees claiming your domain in the From header. Once per UTC day it packs those counts into an XML file, compresses it, and emails it to the address in the rua= tag of your DMARC record. These are aggregate reports, sometimes called RUA reports. They contain no message content, only counts per sending IP with the authentication results for each.

Per RFC 9990, published by the IETF in May 2026 as the Standards Track specification for aggregate reporting, the reporting period is typically a single UTC day starting at 0000 UTC, the XML must be gzip compressed in normal circumstances, and each report covers exactly one policy domain. Reports arrive whether your policy is p=none, p=quarantine or p=reject. They are the only feedback loop DMARC gives you, and reading them is the difference between enforcing safely and blocking your own invoices.

Bar chart showing the DMARC maturity funnel across the top 1.8 million domains in March 2026: 937,931 with a DMARC record, about 553,000 with aggregate reporting, 411,935 at enforcement

Of the top 1.8 million domains, 937,931 (52.1%) publish DMARC, over 553,000 collect aggregate reports, and 411,935 enforce. Only around 9% do both. Source: EasyDMARC, 2026 DMARC Adoption Report, 30 March 2026.

The gap in that chart is the problem this article solves. EasyDMARC's March 2026 study of the top 1.8 million domains found that only about 9% of domains combine an enforcement policy with reporting. A separate DMARCguard scan of 5,499,028 Tranco domains on 27 February 2026 found that 776,918 of the 1,670,975 DMARC domains (46.5%) have no rua= tag at all. Most domain owners who do receive reports never open them, because raw XML looks hostile. It is not. There are only three sections.

Step 1: open the attachment

A genuine report email has a subject like Report Domain: example.com Submitter: google.com Report-ID: 1234567890 and a single attachment. RFC 9990 section 3.5.2 fixes the filename format as receiver!policy-domain!begin-timestamp!end-timestamp.xml.gz, for example google.com!example.com!1757462400!1757548799.xml.gz. The two numbers are Unix timestamps for the start and end of the reporting window, so you can tell the covered day before you open anything.

Decompress it on the command line:

gunzip google.com!example.com!1757462400!1757548799.xml.gz

Some senders, including Microsoft, use zip instead of gzip. In that case use unzip on the file. To pretty-print the result for reading:

xmllint --format google.com!example.com!1757462400!1757548799.xml

Any text editor works too. What you will see is a single feedback element containing report_metadata, policy_published and one or more record blocks.

Step 2: read the three sections

Here is a report trimmed to one record, using the structure from RFC 9990 Appendix B:

<feedback xmlns="urn:ietf:params:xml:ns:dmarc-2.0">
  <version>1.0</version>
  <report_metadata>
    <org_name>google.com</org_name>
    <email>noreply-dmarc-support@google.com</email>
    <report_id>1757548799.example.com</report_id>
    <date_range>
      <begin>1757462400</begin>
      <end>1757548799</end>
    </date_range>
  </report_metadata>
  <policy_published>
    <domain>example.com</domain>
    <adkim>r</adkim>
    <aspf>r</aspf>
    <p>quarantine</p>
    <sp>none</sp>
  </policy_published>
  <record>
    <row>
      <source_ip>192.0.2.123</source_ip>
      <count>123</count>
      <policy_evaluated>
        <disposition>none</disposition>
        <dkim>pass</dkim>
        <spf>fail</spf>
      </policy_evaluated>
    </row>
    <identifiers>
      <envelope_from>example.com</envelope_from>
      <header_from>example.com</header_from>
    </identifiers>
    <auth_results>
      <dkim>
        <domain>example.com</domain>
        <result>pass</result>
        <selector>abc123</selector>
      </dkim>
      <spf>
        <domain>example.com</domain>
        <result>fail</result>
      </spf>
    </auth_results>
  </record>
</feedback>

Older reports use the namespace http://dmarc.org/dmarc-xml/0.1 from RFC 7489. The fields are the same, so read them the same way.

ElementWhat it tells youHow to use it
report_metadata / org_nameWhich receiver generated the reportGroup findings per receiver; Google and Microsoft together usually cover most of your volume
date_rangeUnix timestamps of the covered windowMatch spikes to campaigns or incidents on that day
policy_publishedYour DMARC record as the receiver read itIf p differs from what you published, DNS had not propagated or you have two records
source_ipThe IP that delivered the message to the receiverReverse-lookup it; this is your sender inventory
countMessages from that IP with identical resultsBig counts are your real mail streams; tiny counts are noise or probes
policy_evaluated / dkim and spfAligned DKIM and aligned SPF resultsThis is the DMARC verdict, after alignment, not the raw check
dispositionWhat the receiver did: none, quarantine, reject, or pass in RFC 9990 reportsTells you what actually happened to the mail
reasonWhy a receiver overrode your policymailing_list, trusted_forwarder, local_policy, policy_test_mode or other
header_fromThe domain in the visible From headerThe domain that DMARC is protecting in this row
envelope_fromThe RFC5321.MailFrom domain SPF checkedIf it differs from header_from, SPF cannot align
auth_results / dkimRaw DKIM result, signing domain and selectorA pass here with a fail in policy_evaluated means the d= domain is not yours
auth_results / spfRaw SPF result and the domain checkedA pass here with a fail above means the envelope domain is not aligned

The one distinction that trips up almost everyone: auth_results is the raw check, policy_evaluated is the check after alignment. DMARC only counts SPF or DKIM as passing if the authenticated domain matches your header_from domain. A marketing platform signing with its own domain will show DKIM pass in auth_results and DKIM fail in policy_evaluated. That is not a broken signature. It is an unaligned one.

Step 3: classify every row

Two people reviewing DMARC report data on laptops at a shared desk

Once the fields make sense, reading a report is pattern matching. These seven patterns cover nearly every row you will encounter.

#What the row showsMost likely causeWhat to do
1SPF aligned pass, DKIM aligned pass, high countYour own mail server or a correctly configured serviceNothing. This is the target state
2SPF aligned pass, DKIM fail or missingA service you authorised in SPF that is not signing with your domainEnable DKIM at that service and publish its CNAME or TXT selector
3SPF fail, DKIM aligned pass, envelope_from is another domainForwarding, a mailing list, or a platform using its own bounce domainNormal. DMARC still passes. Do not add the forwarder to SPF
4Raw DKIM pass with signing domain not yours, aligned DKIM failThird-party sender signing with its own default keyAsk the vendor for a custom signing domain (a CNAME under yours)
5Raw SPF pass for envelope_from, aligned SPF failVendor uses its own return-path domainSet a custom return-path or bounce domain at the vendor, or rely on DKIM
6Everything fails, source_ip belongs to a cloud or hosting range you do not recognise, count in the hundreds or thousandsSpoofing or a phishing campaign using your domainLeave it failing. Move toward p=reject so receivers drop it
7Everything fails, low count, reason says mailing_list or trusted_forwarderReceiver exempted the message from your policyInformational. Nothing to fix on your side

For a row you cannot place, reverse-lookup the IP with dig -x 192.0.2.123 +short or host 192.0.2.123, then check the SPF include for your suspected vendor. A PTR record ending in outbound.protection.outlook.com, google.com, amazonses.com, sendgrid.net or mailgun.org usually points straight at the responsible service.

Reading reports at volume

A domain with a few senders produces a handful of files a day, and hand reading works. Above that, use an analyser. A typical analyser ingests the rua= mailbox, decompresses each file, and rolls the rows up by source, so you see "Microsoft 365: 12,400 messages, 100% aligned" rather than forty XML files. Free options exist, and FortifyNet's own scan will tell you whether a rua= tag is even present and syntactically correct.

Two habits matter more than the tool. First, watch policy_published after every DNS change: receivers cache DMARC records, so a report covering the day you changed p= may show the old policy, and RFC 9990 section 3.3 explicitly allows a mix. Second, keep reading after you reach p=reject. New SaaS tools, rotated DKIM keys and edited SPF records all show up as a new pattern 2, 4 or 5 row the next day, long before your customers notice bounces.

What RFC 9990 changed for readers

The May 2026 standard, which obsoletes the reporting parts of RFC 7489 from 2015, matters if you parse reports yourself or evaluate a vendor.

Field or ruleRFC 7489 (2015)RFC 9990 (2026)
XML namespacehttp://dmarc.org/dmarc-xml/0.1urn:ietf:params:xml:ns:dmarc-2.0
DKIM selectorOptionalRequired whenever a DKIM result is reported
disposition valuesnone, quarantine, rejectAdds pass
Override reasonsforwarded, sampled_out, trusted_forwarder, mailing_list, local_policy, otherlocal_policy, mailing_list, other, policy_test_mode, trusted_forwarder
discovery_methodNot presentOptional: psl or treewalk
generatorNot presentOptional name and version of the reporting software
envelope_fromOptionalOptional, may be empty for bounces with a null sender
Unknown elementsUndefinedMust be ignored, not treated as errors

Every major receiver still sends legacy-shaped reports in September 2026, and will for a long time. Read both formats the same way and never discard a report because it has a field you do not recognise.

FAQ

Why do I get DMARC reports for mail I never sent? Because someone else is sending it. Aggregate reports cover every message that claimed your domain in the From header, including spoofed ones. A row with a high count, an unknown IP and failures on both SPF and DKIM is exactly the spoofing you set up DMARC to catch.

How many reports should I expect per day? One per reporting receiver per day per domain, so typically 3 to 15 files for a small business. RFC 9990 sets the period to a single UTC day. Very large receivers may split a day into several files.

What does disposition none mean when I have p=quarantine? Either the message passed DMARC, so no policy applied, or the receiver overrode your policy and the reason element says why. Check policy_evaluated: if both aligned results are pass, none is the correct disposition.

Do DMARC reports contain email content or personal data? Aggregate reports contain sending IPs, counts and authentication results, nothing from the message body or headers beyond the From domain. Failure reports (RUF, defined in RFC 9991) can contain headers and are rarely sent by major providers.

Can I stop receiving reports? Remove the rua= tag and receivers stop within a day. You lose all visibility into spoofing and misconfiguration when you do, so pointing rua= at an analyser is the better option.

Check whether your reports are even arriving

Before you spend an evening with XML, it helps to know whether your DMARC record asks for reports at all, whether the rua= address is authorised, and whether SPF and DKIM are set up on the senders you already know about. FortifyNet's free scan reads your DMARC, SPF and DKIM records and flags what is missing in about 60 seconds, with no signup. Run a free scan at FortifyNet.

Related guides: DMARC Monitoring: How to Reach p=reject Safely · How to Set Up DMARC, Step by Step · What Is DKIM? · SPF Record Checker

Frequently Asked Questions

#dmarc#dmarc-reports#email-authentication#rua#email-security

Check your domain now

Run a free security audit and see if your domain has the issues described in this article.

Cookie Settings

We use cookies to improve your experience. You can choose which cookies to accept.