Skip to content
🚀 10 tools live, free forever — the toolbox keeps growing
Home›Blog›How to Read a DMARC Report (Without Drowning in XML)
Guides

How to Read a DMARC Report (Without Drowning in XML)

What a DMARC aggregate report actually contains, how to read the XML row by row, how to tell your own forgotten senders from real spoofing, why forwarders look like attackers, and how to get safely from p=none to p=reject.

✍ By the Founder & CEO, Team BuildToolForge🗓 2026-10-17⏱ 11 min
dmarcemailspfdkimemail spoofing
Email Security Guide2026

DMARC Reports
Decoded

What a DMARC aggregate report contains

Aggregate XML · SPF & DKIM alignment · Enforcement

dmarc · aggregate.xml
source_ip203.0.113.9
count128
spfpass
dkimfail
✓ one sender, 128 messages · DKIM is the thing to fix
Report blocks
metadata
Reporter
policy
Published
record
Per sender
row
Volume & IP
auth
SPF & DKIM
identifiers
From domain
Spot real spoofingFind forgotten sendersExplain forwardersReach p=reject

What a DMARC report actually is

Publish a DMARC record with an rua= address and mailbox providers start sending you aggregate reports: one XML file per provider per day, listing every IP that sent mail claiming to be your domain, how many messages each one sent, and whether SPF and DKIM passed and aligned.

Two things it is worth knowing before you open one:

  • Aggregate reports contain no message content. No subjects, no recipients, no bodies. They are counts grouped by sending IP. That is why they are safe to collect and why they cannot tell you which message failed.
  • They are not the same as forensic reports. A ruf= address asks for per-message failure samples, which do contain headers and sometimes more. Most providers no longer send them at all, for privacy reasons, so in practice DMARC visibility means aggregate reports.

What they give you is the one thing you cannot get any other way: a list of everything in the world sending email as your domain, including the systems inside your own company that nobody remembers setting up. That inventory is the entire point, and it is what makes a safe move to enforcement possible.

Getting the reports in the first place

A minimal record that only collects data, changing nothing about delivery:

v=DMARC1; p=none; rua=mailto:dmarc@example.com

It goes at _dmarc.example.com as a TXT record. p=none means “apply no policy, just tell me” — it is the correct starting point and it cannot hurt your delivery. Check the record is actually live and readable with a DNS lookup tool before waiting on reports that will never arrive.

Two practical notes. Reports arrive daily and in bulk, so send them to a dedicated mailbox rather than your own. And if you want reports sent to an address at a different domain, that domain has to authorise it with its own DNS record — a missing authorisation record is the commonest reason reports silently never show up.

Reading the XML: three blocks

Every aggregate report has the same shape. Once you have seen it once it stops being intimidating.

Block 1: who sent the report

<report_metadata> names the reporting organisation, gives a report ID and a date range. The date range is the thing to notice: reports are usually a 24-hour window, and they arrive a day or two late, so the IP you are looking at did its sending in the past.

Block 2: the policy they saw

<policy_published> is your own DMARC record as that provider read it: p (your policy), sp (subdomain policy), pct (the percentage you asked to be enforced), and the alignment modes. This block is a useful sanity check — if it does not match what you think you published, your record has a syntax problem or has not propagated yet.

Block 3: the rows that matter

Then a series of <record> elements. Each one is a group of messages from one IP with one outcome, not a single email. Each contains a <row> with the source IP and a count, a <policy_evaluated> with the DMARC result and what the provider actually did, and an <auth_results> with the underlying SPF and DKIM results.

Reading one row in practice

Work through it in this order, and the row answers itself:

  1. Who is the IP? Look it up. A name like a known email platform means it is a service of yours; an unfamiliar network is the one to investigate.
  2. How many messages? Two messages is noise. Twenty thousand is a system.
  3. What does <policy_evaluated><disposition> say? none, quarantine or reject — what the provider did about it.
  4. Did SPF and DKIM pass, and did they align? That pair is the whole diagnosis, and it is the next section.

The four combinations, and what each means

DMARC passes if either SPF or DKIM passes and is aligned with the visible From: domain. That gives four cases:

  • SPF pass + DKIM pass. Your properly configured sender. Nothing to do.
  • SPF pass, DKIM fail. Usually a service sending from an authorised IP without signing. Get DKIM signing enabled — SPF alone is fragile, because it breaks the moment a message is forwarded.
  • SPF fail, DKIM pass. Most often legitimate forwarded mail: the forwarder's IP is not in your SPF record, but the signature survived. DMARC passes on DKIM alone, which is exactly the design working.
  • Both fail. Either a sender of yours that was never configured, or someone spoofing you. Telling those apart is the next section.

Watch for one trap in the XML: a result can read pass in <auth_results> and still fail DMARC, because the authenticated domain was not aligned with the From: domain. A platform signing with its own domain produces exactly that. If that is confusing, why an SPF pass is not a DMARC pass goes through alignment in detail.

Telling your own senders from spoofing

Almost everyone's first reports look alarming and almost none of it is an attack. Sort the failing IPs into three piles:

  • Yours, misconfigured. A CRM, an invoicing system, a ticketing tool, a marketing platform, an application server. Clues: the IP resolves to a recognisable provider, the volume is steady day after day, and the messages are being delivered. Fix: authorise it properly, preferably with DKIM.
  • Forwarders. Low volume, scattered IPs, universities and small mail hosts, SPF failing while DKIM passes. Not a problem, and not fixable from your side.
  • Actual spoofing. Unfamiliar networks, often bursty, frequently foreign to your business, failing both checks. The reassuring part: with a policy in place this mail is already being rejected, which is the whole point.

The sequence matters. Identify everything in the first pile before you tighten the policy, because enforcement turns a misconfigured sender of yours into undelivered mail.

Why forwarders look like attackers

This confuses everyone once. A mailing list or an alias relays your message from its own server, so your SPF record is checked against an IP you never authorised and fails — correctly. The report shows an unknown IP failing SPF while sending as you, which reads exactly like abuse.

Two tells separate them. Forwarded mail usually still passes DKIM, because the signature travels with the message, so DMARC passes overall. And the volume is small and spread across many unrelated IPs rather than concentrated. Mailing lists are the exception that can break both: some rewrite the subject or append a footer, which invalidates the DKIM signature and leaves a genuine message failing everything.

Using the reports to get to enforcement

The reports exist to make this move safe. A workable sequence:

  • Stay at p=none until the reports are boring — typically a few weeks. You are waiting until every legitimate sender you find has been authorised and nothing new appears.
  • Fix senders as you find them, preferring DKIM. A sender with DKIM survives forwarding; one with only SPF does not.
  • Move to p=quarantine, optionally with pct= to ramp. Failing mail goes to spam rather than disappearing, so a mistake is recoverable.
  • Then p=reject, once quarantine has been quiet. This is the point at which spoofed mail using your domain is actually refused.
  • Keep reading the reports afterwards. A new vendor added six months from now will show up as a failing IP, and you want to see it before someone tells you their invoices are bouncing.

Do not set p=reject on day one. The only thing that makes enforcement safe is the inventory the reports give you, and that takes weeks to become complete. The guide to SPF, DKIM and DMARC covers the records themselves.

Common mistakes

  • Jumping to p=reject before reading reports. The forgotten system is usually the one that invoices your customers.
  • Reading each row as one message. A row is a group of messages from one IP with one outcome.
  • Treating every failing IP as an attacker. Most early failures are your own services and ordinary forwarding.
  • Assuming a pass in auth_results means DMARC passed. Without alignment to the From: domain it does not.
  • Sending reports to a monitored human mailbox. They arrive daily from dozens of providers. Use a dedicated address.
  • Forgetting the subdomain policy. Without sp=, subdomains inherit p, which may not be what you want during a rollout.
  • Fixing SPF only. SPF breaks on forwarding; DKIM is what carries DMARC through it.
  • Turning reporting off once you reach reject. That is when it starts being an early warning system.

The short version

A DMARC aggregate report is a daily XML list of every IP sending as your domain, with counts and SPF/DKIM results — no message content. Read each row in four steps: identify the IP, look at the volume, read the disposition, then check whether SPF or DKIM passed and aligned. Expect most early failures to be your own unconfigured services and ordinary forwarding rather than spoofing, fix senders with DKIM wherever you can, and only move from p=none to quarantine and then reject once the reports have gone quiet. Check your _dmarc record is published and readable with the free DNS lookup tool, and if an SPF result in a report looks contradictory, the SPF troubleshooting guide explains why.

Related tools and guides:

Frequently Asked Questions

What is in a DMARC aggregate report?⌄

An XML file, usually covering 24 hours from one mailbox provider, listing every IP that sent mail claiming to be your domain, how many messages each sent, whether SPF and DKIM passed and aligned, and what the provider did about it. It contains no message content — no subjects, recipients or bodies.

How do I start receiving DMARC reports?⌄

Publish a TXT record at _dmarc.yourdomain.com reading v=DMARC1; p=none; rua=mailto:your address. p=none applies no policy, so it cannot affect delivery. Use a dedicated mailbox, since reports arrive daily from many providers, and note that sending reports to an address at another domain requires that domain to authorise it with its own DNS record.

Why do DMARC reports show IPs I do not recognise?⌄

Usually for two innocent reasons: a service of yours that was never authorised — a CRM, invoicing or ticketing system — or ordinary mail forwarding, where the forwarder relays from its own IP and fails SPF while DKIM still passes. Genuine spoofing tends to be bursty, from unrelated networks, and fails both checks.

When is it safe to move to p=reject?⌄

Once your reports have been quiet for a few weeks: every legitimate sender identified and authorised, preferably with DKIM, and nothing new appearing. Move through p=quarantine first, where failing mail goes to spam rather than being refused, so any mistake is recoverable.

Why does a row show SPF pass but DMARC fail?⌄

Because DMARC requires alignment as well as authentication: the domain that passed SPF must match the visible From: domain. A platform sending with its own return path passes SPF on its own domain, which does nothing for yours, so the alignment check fails and DMARC fails with it.

About the author
Founder & CEO, BuildToolForge
Follow on X: @Buildtoolforge

15+ years of hands-on experience in web development and security. Focused on practical web security: keeping websites secure, reliable and easy to troubleshoot. BuildToolForge exists to make these checks free, private and understandable. Tools run in your browser wherever possible, and nothing you enter into a tool is stored.

How we write our guides: Every guide is written from hands-on experience, checked against the official standards, and tested with our own tools on real domains. We update guides when standards or tools change. Found a mistake? Email contact@buildtoolforge.com.

Last updated: November 2, 2026