✉ Email deliverability

DMARC aggregate reports: how to read them and what to look for

The structure of DMARC rua reports in XML, how to interpret records, results and alignment, and how to tell legitimate sources from spoofing attempts.

Publishing a DMARC record with the rua= tag is like switching on a camera pointed at your own domain. Every day the large mailbox providers send the address you specified a summary of all the messages they received with your domain in From: which servers they came from, how many there were, whether they passed SPF and DKIM. The catch is that these reports arrive as compressed XML and, the first time you open one, look unreadable. Learning to read them is the step that separates a decorative DMARC from one that actually protects.

How to enable them

All it takes is a destination address in the DMARC record:

_dmarc.example.com.  TXT  "v=DMARC1; p=none; rua=mailto:dmarc-report@example.com"

If the address belongs to a domain other than the one being monitored, the receiving domain must publish an authorization record, otherwise providers will not send the reports. The mechanism is designed to stop someone from flooding another party's mailbox with reports.

Use a dedicated mailbox: even a small domain receives dozens of reports a day, and a personal inbox quickly becomes unmanageable.

The structure of a report

Each report is an XML file, usually compressed as zip or gzip, divided into three parts.

Metadata

It states who generated the report (org_name), the report identifier and the time range covered, expressed as Unix timestamps. The range is usually 24 hours.

Published policy

It shows the policy the receiver read in your DNS at evaluation time: p, sp, adkim, aspf. It lets you check that the record was interpreted the way you intended.

Records

This is the important part. Each record element groups the messages coming from the same IP address with the same results. A simplified example:

<record>
  <row>
    <source_ip>192.0.2.25</source_ip>
    <count>312</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><result>pass</result></dkim>
    <spf><domain>bounce.example.net</domain><result>pass</result></spf>
  </auth_results>
</record>

Reading a record without getting confused

The point that causes the most mistakes is the difference between policy_evaluated and auth_results.

  • auth_results shows the raw SPF and DKIM results, with the domain each was evaluated on.
  • policy_evaluated shows the result for DMARC purposes, that is, taking alignment into account.

In the example, SPF in auth_results is pass, but on the domain bounce.example.net, which does not match From. For DMARC, SPF therefore counts as fail. DKIM, on the other hand, passes and is aligned, because the signature belongs to example.com. The message passes DMARC thanks to DKIM. The disposition shows what the receiver did: none, quarantine or reject.

Classifying sources

The practical goal is to build a list of every source sending with your domain and sort them into three groups.

Group How to recognize it Action
Legitimate and configured aligned DKIM or SPF passing none
Legitimate but not configured IP of one of your providers, DMARC fail configure DKIM or the bounce domain
Illegitimate unknown IPs, often erratic volumes let the policy block them

To identify an IP, start with its PTR record and the owner of the address block. An IP belonging to your newsletter platform's provider is almost certainly legitimate; one that resolves to a residential connection on another continent, with a few dozen messages all failing, most likely isn't.

Watch out for one common case: forwarding. When a recipient automatically forwards mail to another mailbox, the message arrives from a server that isn't yours. SPF fails, but DKIM often remains valid. These records show up as IPs of well-known providers with DKIM passing and SPF failing: they are not attacks.

Tools so you don't read XML by hand

Reading files one by one is fine for understanding the format, not for daily work. There are commercial services that collect and visualize reports, and open source tools that parse them and load them into a database or a dashboard. In my work I prefer a solution that keeps the raw data: when you investigate an anomaly, you need to get back to the individual record.

There are also forensic reports (ruf=), which contain details about individual failed messages. Many large providers don't send them for privacy reasons, so it is not wise to rely on them.

A review routine

  1. Every week, check that volumes from known sources match actual activity.
  2. Look for new sources with DMARC fail and significant volumes: often it is a department that enabled a service without telling anyone.
  3. Check that no legitimate source relies on SPF alone.
  4. Before tightening the policy, make sure legitimate unaligned sources are zero or negligible.

In short

  • Aggregate reports arrive as XML, one per provider per day, at the address given in rua=.
  • auth_results shows raw results, policy_evaluated shows the ones that count for DMARC.
  • The goal is to classify each source as legitimate and configured, legitimate but needing fixes, or illegitimate.
  • Forwarding produces SPF fail with DKIM pass and should not be mistaken for an attack.
  • An aggregation tool becomes indispensable after the first few days of monitoring.
MM
Marco Marzaduri

Marco Marzaduri works in cybersecurity, digital forensics and web development. A computer science graduate, he combines rigorous technical analysis with attention to the people who use technology.

Read also