PlainDMARC

How to Read DMARC Reports (Aggregate XML Report Example, Explained)

DMARC aggregate reports arrive as dense XML files from mailbox providers. Here is how to read them in plain English — what every field means, and how to tell legitimate senders apart from spoofing and forwarding.

If you have published a DMARC record, your inbox (or a mailbox you named in the rua tag) is now receiving daily XML attachments. They look intimidating, but each one answers a simple question: "Who sent email claiming to be from your domain yesterday, and did it pass authentication?" This guide walks through a real-looking DMARC aggregate report example line by line so you can start making sense of them today.

What a DMARC aggregate (rua) report actually is

DMARC has two report types. The one you get flooded with is the aggregate report, requested by the rua= tag in your DNS record. It is a once-per-day XML summary from a single mailbox provider, grouping all the messages that used your domain in the From: header into rows by sending IP address and authentication result.

Aggregate reports contain no message content and no recipient addresses — they are privacy-safe statistics. That is different from forensic (ruf) reports, which can include message-level detail and which most providers no longer send.

Who sends them

A domain that sends to many places can generate a dozen or more XML files every single day. That volume is exactly why reading raw XML by hand breaks down quickly — more on that below.

A DMARC XML report, explained

Here is a trimmed but realistic aggregate report. Google wraps this in an XML file named something like google.com!yourdomain.com!1730332800!1730419200.xml. Read the annotations underneath.

<feedback>
  <report_metadata>
    <org_name>google.com</org_name>
    <email>noreply-dmarc-support@google.com</email>
    <report_id>14785236901234567890</report_id>
    <date_range>
      <begin>1730332800</begin>
      <end>1730419200</end>
    </date_range>
  </report_metadata>
  <policy_published>
    <domain>yourdomain.com</domain>
    <adkim>r</adkim>
    <aspf>r</aspf>
    <p>quarantine</p>
    <pct>100</pct>
  </policy_published>
  <record>
    <row>
      <source_ip>209.85.220.41</source_ip>
      <count>428</count>
      <policy_evaluated>
        <disposition>none</disposition>
        <dkim>pass</dkim>
        <spf>pass</spf>
      </policy_evaluated>
    </row>
    <identifiers>
      <header_from>yourdomain.com</header_from>
    </identifiers>
    <auth_results>
      <dkim>
        <domain>yourdomain.com</domain>
        <result>pass</result>
      </dkim>
      <spf>
        <domain>yourdomain.com</domain>
        <result>pass</result>
      </spf>
    </auth_results>
  </record>
</feedback>

The header block: who and when

org_name tells you the receiver that generated the report (here, google.com). The date_range values are Unix timestamps — 1730332800 to 1730419200 is a 24-hour window. Most tools convert these to a human date for you.

policy_published: your own settings, echoed back

This block simply repeats the DMARC policy the receiver found in your DNS. p=quarantine is your enforcement level, pct=100 means it applies to all mail, and adkim=r / aspf=r mean "relaxed" alignment. Useful as a sanity check that your published record matches what you intended.

The record row: the field that matters most

Each <record> is one group of messages that shared the same IP and result. Reading our example:

FieldValueWhat it means
source_ip209.85.220.41The server that sent the mail. This is a Google IP — expected if you send via Google Workspace.
count428428 messages were sent from that IP during the window. Volume, not a problem indicator by itself.
dispositionnoneWhat the receiver did: none = delivered normally, quarantine = spam folder, reject = bounced.
dkim / spf (policy_evaluated)pass / passThe aligned result DMARC used to make its decision.

The auth_results block below shows the raw checks: DKIM signed with yourdomain.com and passed, SPF authorised yourdomain.com and passed. Because those signing/authorising domains match your header_from, the mail is aligned — and DMARC passes.

Alignment is the whole game

A message can pass SPF or DKIM and still fail DMARC. Alignment means the domain that passed SPF/DKIM matches the visible From: domain. In our 428-message row everything lines up, so the row is a clean DMARC pass. When those domains differ, you get a pass on the raw check but a fail on policy_evaluated — the signal you are hunting for.

Legitimate sender vs spoofing vs forwarding

Once you can read a row, you can classify it. Three patterns cover almost everything you will see:

The practical rule: trust DKIM alignment, investigate anything that fails both, and expect forwarding to create harmless SPF-only failures.

Why reading raw XML every day doesn't scale

One clean report is easy. The reality is messier:

Manually parsing XML is fine for a demo and impossible as an operating habit. What you actually want is a verdict: is everything fine, or is there something to look at?

Stop parsing XML by hand

PlainDMARC turns these reports into a plain-English weekly verdict for ALL your domains at one flat price — no per-domain fees, no dashboards to babysit. Join the waitlist and we will read the XML so you never have to.

Join the waitlist Try the free DMARC checker

Frequently asked questions

What does count mean in a DMARC aggregate report?

The count value is the number of email messages that shared the same source IP and authentication result during the report's 24-hour window. In our example, <count>428</count> means 428 messages came from that IP with identical results. A high count is normal for your real sending servers; a high count from an unknown IP that fails authentication is the pattern worth investigating.

What is the difference between DKIM pass and DMARC alignment?

DKIM pass means the cryptographic signature was valid. DMARC alignment additionally requires that the domain in that signature matches the visible From: address. A message can show dkim=pass in auth_results yet still fail DMARC if the signing domain does not align with your header_from. Alignment, not the raw pass, is what determines the final DMARC verdict.

Should I move to p=reject as soon as I see SPF failures?

No. Legitimate forwarding routinely breaks SPF while DKIM still passes, so SPF-only failures are usually harmless. Move toward p=quarantine and then p=reject only after you have confirmed that all your genuine sending sources pass aligned DKIM. Tightening policy on the strength of forwarding-related SPF failures can quietly block real mail.