Skip to content
DERKONLINE

Read Your DMARC Reports and Find Who Is Spoofing Your Domain

Your DMARC reports already name everyone spoofing your domain. Parse the RUA XML into a sender map and walk the policy to enforcement.

Derrick S. K. Siawor6 min read

You published a DMARC record, set the policy to p=none, and the daily XML reports started arriving in your inbox. Now they sit there unread, a steady drip of attachments named like google.com!yourdomain.com!1718...xml.gz, each one a wall of angle brackets. Most teams stop here. They have DMARC, technically, and no idea what it is telling them.

That is the expensive mistake. Those reports are a map of every server on the internet sending mail as your domain, the legitimate ones and the forgers alike. Read them properly and you learn exactly who is spoofing you, which of your own services are misconfigured, and when it is safe to turn on enforcement. Ignore them and your domain stays an open relay for phishers, with you holding the receipts and not looking.

What a DMARC aggregate report actually is

A DMARC aggregate report (the rua in your DMARC record) is an XML file that receiving mail providers, Google, Microsoft, Yahoo, and the rest, send daily to the address you specified. Each report summarizes the mail they saw claiming to be from your domain over a 24-hour window. For every distinct sending source, it tells you:

  • The source IP address that sent the mail.
  • The message volume from that IP.
  • The SPF result and the DKIM result.
  • Whether each of those results aligned with the domain in the visible From header.
  • The DMARC disposition that was applied (none, quarantine, or reject).

That alignment field is the whole game, and it is the part people miss. SPF can pass and DKIM can pass while DMARC still fails, because DMARC does not just ask "did authentication pass." It asks "did authentication pass for the same domain the recipient sees in the From line." A spammer can send through a server with valid SPF for their own domain and still fail DMARC for yours, because the From header says your domain and SPF passed for theirs. Alignment is what makes DMARC stop spoofing that SPF and DKIM alone would wave through. If your three records are not set up so they actually pass in the first place, the reports will be noise.

Reading the raw XML

Strip away the boilerplate and a single record block looks like this:

<record>
  <row>
    <source_ip>203.0.113.45</source_ip>
    <count>1820</count>
    <policy_evaluated>
      <disposition>none</disposition>
      <dkim>fail</dkim>
      <spf>fail</spf>
    </policy_evaluated>
  </row>
  <identifiers>
    <header_from>yourdomain.com</header_from>
  </identifiers>
  <auth_results>
    <spf><domain>sketchy-host.ru</domain><result>pass</result></spf>
  </auth_results>
</record>

Read that out loud. An IP you do not recognize sent 1,820 messages claiming to be from your domain. SPF passed, but for sketchy-host.ru, not for you, so it did not align. DKIM failed entirely. DMARC's evaluated result is dkim: fail and spf: fail. Disposition is none, which means your policy let it through anyway, because you are still in monitoring mode. That single block is a spoofing campaign, fully documented, and the only thing missing is someone reading it.

Turn the pile of XML into a sender map

Nobody should read these by hand at volume. The right move is to parse every report into a structured store and build one view: a map of sources sending as your domain, grouped and sorted by what matters.

The fields to extract per record are source IP, count, header-from domain, SPF result and its auth domain, DKIM result and its auth domain, and the evaluated alignment. Aggregate across all reports and bucket each sending IP into one of three categories:

  1. Authenticated and aligned. SPF or DKIM passes and aligns with your domain. These are your real services: your mail server, your transactional email provider, your marketing platform. The map will often expose that these two streams are tangled on one domain, which is the cue to split transactional and marketing mail across subdomains the right way. You want these passing.
  2. Yours but broken. The mail is from a service you actually use, but it is failing alignment. This is a misconfiguration, a missing SPF include, an unsigned DKIM, a third-party sender you forgot to authorize. These are fixable and they are the reason you cannot safely enforce yet.
  3. Not yours. Unknown IPs, often from networks you have no relationship with, sending at scale with everything failing. This is the spoofing. If you see IPs you do not recognize sending mail in your name at volume, that is your forgery problem made visible.

Once the map is built, the actions are obvious. Authorize the real senders by fixing their SPF and DKIM until they align. Leave the forgers exactly where they are, failing, so that when you raise enforcement they get blocked.

You can write the parser in an afternoon (any language with an XML library and a database will do), or use one of the hosted DMARC processors that ingest the reports and render the sender map for you. Either way, the goal is identical: never read raw XML again, read the map.

From p=none to p=reject without breaking your own mail

DMARC rollout: parse reports into a sender map, bucket sources, walk p=none to quarantine to reject

The reason DMARC reports exist is to let you turn on enforcement safely. The sequence is:

  1. Start at p=none. Collect reports for two to four weeks. Mail flows normally; you are only watching.
  2. Read the map and fix category two. Every legitimate sender must pass and align before you tighten. This is where most of the work is, and where rushing causes self-inflicted outages.
  3. Move to p=quarantine, often with a percentage tag (pct=25) so only a fraction of failing mail goes to spam at first. Keep watching the reports.
  4. Move to p=reject once your legitimate sources are clean and the only mail failing is the forgery you want blocked.

This staged walk is the careful version of moving DMARC from none to reject without killing legitimate email, and once you reach enforcement you can layer on a verified logo next to every email with BIMI, which requires p=quarantine or stricter. At p=reject, the spoofed mail in your reports stops landing in inboxes. The campaign that was sending 1,820 messages a day as you is now bouncing at the recipient's server. You did not negotiate with the attacker. You just stopped vouching for them.

Why this is worth doing right

Email deliverability and domain trust are the same problem viewed from two ends. A domain that lets anyone spoof it gets its real mail filtered harder, because receivers cannot tell your legitimate messages from the forgeries. Enforced DMARC is now effectively required to reach the major inbox providers at volume, part of meeting Google and Yahoo bulk sender rules, and it is one of the clearest signals that you run a tight sending domain. It is the same foundation that has to be in place before you warm a brand new sending domain to full volume, because warming an unauthenticated domain just teaches receivers to distrust you faster. Get the authentication wrong and you end up fighting to get out of the Gmail spam folder instead of preventing the problem.

This is the work we do on every email deliverability engagement: ingest the reports, build the sender map, fix the alignment on the real senders, and walk the policy up to enforcement without dropping a single legitimate message. It is the same discipline behind the email accounts we set up, where authentication is correct from the first message rather than retrofitted after a deliverability crisis.

The reports are already arriving. They already contain the name of everyone forging your domain and every service of yours that is quietly broken. The only question is whether anyone is reading them. Start parsing, build the map, and the path from "we have DMARC" to "nobody can spoof us" stops being a mystery and becomes a checklist.