← Back to Learning Hub

Email Delivery • Intermediate • 5 min read

How to Read a DMARC Aggregate (RUA) Report

Decode a DMARC aggregate RUA report: read the report metadata, the published policy, and the per-source rows for SPF, DKIM, alignment, and disposition.

A DMARC aggregate report (the RUA report) is an XML file a mailbox provider sends you once a day that summarizes every message it saw claiming to come from your domain, grouped by sending IP. To read it, you open the XML and work through three parts: who sent the report and for what time window, the policy the receiver applied, and a set of rows that each show a source IP, a message count, whether SPF and DKIM passed, whether they aligned with your domain, and what the receiver finally did with the mail. Once you can map those fields, you can spot unknown senders, see which authentication method is actually carrying your mail, and move safely from monitoring toward enforcement.

Aggregate reports are defined in RFC 7489 and arrive at whatever address you listed in the rua= tag of your DMARC record. They are statistics, not copies of mail: there are no message bodies, subject lines, or recipient addresses inside. That is by design, and it is why you can safely collect them at scale.

The three top-level blocks

Every aggregate report is a single <feedback> document that contains three branches. Learn these and the rest is detail.

  • report_metadata tells you who generated the report, a contact address, a unique report ID, and the date range (in Unix epoch seconds, UTC).
  • policy_published echoes your DMARC record exactly as the receiver read it when it processed the mail, so you can confirm the receiver saw the policy you think you published.
  • record repeats once per sending source. This is where the real work happens.

Reading report_metadata and policy_published

The header blocks are short. Here is a typical pair, trimmed for clarity.

<report_metadata>
  <org_name>google.com</org_name>
  <email>noreply-dmarc-support@google.com</email>
  <report_id>14925017763571250123</report_id>
  <date_range>
    <begin>1760054400</begin>
    <end>1760140800</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>

The two date values are epoch timestamps. On a Unix shell you can convert them with date -d @1760054400 to confirm the 24 hour window. In policy_published, adkim and aspf are the alignment modes (r for relaxed, s for strict), p is your main policy, and sp is the subdomain policy. If this block shows p=none when you meant to enforce, your record change has not propagated yet or you edited the wrong host.

Reading the record rows: where the answers live

Each <record> has three children: row, identifiers, and auth_results. A single record looks like this.

<record>
  <row>
    <source_ip>209.85.220.41</source_ip>
    <count>128</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>
      <selector>s1</selector>
      <result>pass</result>
    </dkim>
  </auth_results>
</record>

The single most important distinction is between auth_results and policy_evaluated. The auth_results block is the raw outcome: did an SPF check pass, and for which domain, and did a DKIM signature validate, and for which domain and selector. The policy_evaluated block is the aligned outcome: DMARC only counts a pass if the authenticated domain matches the header_from domain under your alignment mode. A message can show SPF pass in auth_results yet fail in policy_evaluated, because the SPF check passed for an unrelated envelope domain that does not align with your From header.

Field reference

FieldWhereWhat it tells you
source_iprowThe IP that sent the mail. Start every investigation here.
countrowHow many messages this roll-up represents.
dispositionpolicy_evaluatedWhat the receiver did: none, quarantine, or reject.
dkim / spfpolicy_evaluatedThe aligned DMARC verdict for each method.
header_fromidentifiersThe visible From domain the reader sees.
spf.domain / resultauth_resultsThe envelope domain SPF checked and its raw result.
dkim.domain / selector / resultauth_resultsThe signing domain, selector, and raw signature result.

What to look for

When you scan a batch of reports, you are hunting for a short list of patterns.

  1. Unknown sending sources. Any source_ip with a healthy count that you cannot identify is either a legitimate service nobody told you about (a CRM, a help desk, a newsletter tool) or a spoofer. Reverse-resolve the IP and match it against your known senders.
  2. Which method carries alignment. If DKIM passes aligned on your bulk mail but SPF does not, DKIM is doing the work, and you can tolerate SPF breakage. If only SPF aligns, you are fragile, because SPF breaks the moment mail is forwarded.
  3. Forwarders that break SPF. A mailing list or a vacation forwarder relays your mail from its own IP, so SPF fails there. If DKIM still passes aligned, DMARC still passes, which is exactly why you want DKIM alignment working before you enforce.
  4. Spoof sources with full failure. Rows where both SPF and DKIM fail aligned, from IPs unrelated to you, are the mail your policy is meant to stop.

A weekly triage workflow toward enforcement

Reports are only useful if you act on them on a schedule. A simple weekly loop moves you from p=none to p=reject without blocking real mail.

  • Week over week: aggregate all sources, sort by count, and confirm every high-volume IP is a sender you recognize and have authenticated.
  • Fix alignment first: for each legitimate source, make sure at least DKIM passes aligned. Add SPF includes or set up DKIM signing for any laggards.
  • Step the policy: once your known senders are clean for two or three weeks, move from p=none to p=quarantine with a small pct, watch for a week, then raise to full quarantine, then p=reject.
  • Keep watching: enforcement is not the end. New services appear, so keep reading the weekly rollup.

Because the raw XML is tedious at volume, most teams feed these files into a parser or dashboard, but the fields above are what every tool is showing you underneath.

Keep your records clean while you enforce

Every DMARC decision depends on the SPF, DKIM, and DMARC records you actually have live in DNS, and on those changes reaching resolvers worldwide. After you edit a policy, confirm it has propagated with the Valla DNS propagation checker before you expect new reports to reflect it. For the records that feed these reports, see our related guides in the Valla DNS learning hub on creating a DMARC record, setting up DKIM, and reading raw email headers to diagnose a single failing message.

Troubleshooting box

If results look inconsistent, compare authoritative nameservers first, then recursive resolvers by region. Capture snapshots every 10 minutes for deterministic incident timelines.

Try VallaDNS free →