DMARC aggregate reports are XML files that mailbox providers send you, usually once a day, listing every source that sent mail claiming to be your domain and whether it passed SPF, DKIM and alignment. Reading them is how you find every legitimate sender, fix the ones that fail and discover who is spoofing you, so you can move from p=none to p=reject without blocking real mail.
Start here. This guide assumes you already publish a DMARC record. If you do not, follow the guide to authenticate a sending domain first, then come back once reports start to arrive.
The short version
- Ask for reports. Add a rua address to your DMARC record while the policy is p=none.
- Wait and collect. Gather two to four weeks of reports, including any monthly sending.
- Sort the sources. Mark each source IP as legitimate and aligned, legitimate but failing, or unknown.
- Fix what fails. Give each legitimate service an aligned DKIM signature or Return-Path.
- Enforce in steps. Quarantine at a low percentage, raise it, then move to reject.
The DMARC record that requests reports
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com; adkim=r; aspf=r"
| Tag | Meaning |
|---|---|
p | Policy for failing mail: none (monitor), quarantine or reject |
rua | Where to send aggregate reports, as one or more mailto: addresses |
adkim, aspf | Alignment mode: r for relaxed (a subdomain may match), s for strict (exact match) |
sp | Policy for subdomains if different from p |
pct | Percentage of failing mail the policy applies to |
Use a dedicated mailbox. Reports are numerous and large. Send them to a dedicated address or to a report processing service, not to a person.
Sending reports to another domain
If the rua address is on a different domain from the one being reported, that other domain must publish a record that allows it. Otherwise providers will not send reports. For reports about example.com going to reports.example.net:
example.com._report._dmarc.reports.example.net. 3600 IN TXT "v=DMARC1"
What is inside a report
Reports arrive as an attachment, usually gzip or zip compressed. Open one and you will find three parts: information about the sender of the report, the policy the provider found, and a list of rows, one per source IP and result combination.
<feedback>
<report_metadata>
<org_name>google.com</org_name>
<report_id>1234567890</report_id>
<date_range><begin>1759708800</begin><end>1759795199</end></date_range>
</report_metadata>
<policy_published>
<domain>example.com</domain><adkim>r</adkim><aspf>r</aspf><p>none</p><pct>100</pct>
</policy_published>
<record>
<row>
<source_ip>203.0.113.10</source_ip>
<count>1250</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>
<dkim><domain>example.com</domain><selector>mail1</selector><result>pass</result></dkim>
<spf><domain>bounce.example.com</domain><result>pass</result></spf>
</auth_results>
</record>
</feedback>
| Field | What it tells you |
|---|---|
org_name | Which mailbox provider sent the report |
date_range | The period covered, as Unix timestamps |
policy_published | The DMARC policy the provider saw, so you can confirm your record is live |
source_ip and count | The sending server and how many messages it sent in the period |
policy_evaluated | The result that counts for DMARC: dkim and spf here mean aligned pass or fail |
auth_results | The raw SPF and DKIM results and the domains they authenticated, which may differ from the From domain |
header_from | The domain in the visible From address |
Two different results. Inside policy_evaluated, pass means the check passed and aligned. Inside auth_results, pass means only that the check passed for whatever domain it used. A source can pass in auth_results and fail in policy_evaluated. That gap is an alignment problem.
Sort every source into one of three groups
| Group | What you see | What to do |
|---|---|---|
| Legitimate and aligned | A known service, DKIM or SPF aligned in policy_evaluated | Nothing. Keep it that way |
| Legitimate but failing | A known service whose auth_results pass but policy_evaluated fails | Set up aligned DKIM or a custom Return-Path for that service |
| Unknown | An IP you do not recognise, often with many failures | Investigate: a forgotten system, a forwarder or a spoofer. Do not authorise it until you know |
How to identify a source
- Reverse DNS:
dig -x 203.0.113.10 +shortoften names the provider. - Authentication domains: the SPF and DKIM domains in auth_results usually reveal the service.
- Your own inventory: list every tool that sends as your domain: marketing platform, helpdesk, CRM, billing system, website forms, HR tools and servers.
- Volume and pattern: a small, steady count from a known service is normal; a sudden burst from an unknown IP is suspicious.
Summarise reports with a short script
For a first look at a folder of unzipped reports, this script totals messages by source IP and DMARC result:
import glob
import xml.etree.ElementTree as ET
from collections import defaultdict
totals = defaultdict(int)
for path in glob.glob("reports/*.xml"):
for rec in ET.parse(path).getroot().iter("record"):
row = rec.find("row")
ip = row.findtext("source_ip")
ev = row.find("policy_evaluated")
key = (ip, ev.findtext("dkim"), ev.findtext("spf"))
totals[key] += int(row.findtext("count"))
for (ip, dkim, spf), n in sorted(totals.items(), key=lambda x: -x[1]):
print(f"{ip:18} dkim={dkim:5} spf={spf:5} messages={n}")
Fixing alignment failures
| Pattern in the report | Cause | Fix |
|---|---|---|
| SPF passes, DMARC fails | SPF authenticated the provider domain, not yours | Use a custom Return-Path on your own domain |
| DKIM passes, DMARC fails | The signature uses the provider domain in d= | Sign with your own domain: publish the DKIM selector for that service |
| Both fail for a known service | The service is not set up for your domain | Complete its domain authentication |
| Fails only through a forwarder | Forwarding broke SPF, and DKIM was altered | Expect a small tail. Make sure DKIM is present and signs the body |
| Fails for a subdomain | The subdomain has no records of its own | Publish SPF and DKIM for that subdomain |
Move to enforcement in steps
Once the legitimate sources are aligned and only unknown sources fail, raise the policy gradually. Wait at least a week at each step and read the reports before moving on.
| Step | Record | What it does |
|---|---|---|
| 1 | p=none | Monitor only. Collect reports |
| 2 | p=quarantine; pct=10 | Failing mail from 10 percent of messages goes to spam |
| 3 | p=quarantine; pct=50 | Half of failing mail is quarantined |
| 4 | p=quarantine | All failing mail is quarantined |
| 5 | p=reject; pct=25 | A quarter of failing mail is rejected |
| 6 | p=reject | All failing mail is rejected. Keep the rua address |
Do not stop at p=none. It satisfies the minimum rules of Gmail, Yahoo and Outlook.com for bulk senders, but it does not stop spoofing. Enforcement is what protects your domain and your recipients.
Keep monitoring after p=reject
- Review weekly at first, then monthly. New tools that send as your domain will show up as failures.
- Add a step to onboarding: any new system that sends email as your domain gets authenticated before it goes live.
- Protect parked domains: publish p=reject and an empty SPF record on domains you do not send from.
- Watch for BIMI readiness: an enforced DMARC policy is a prerequisite if you later want your logo to appear in the inbox.
Want a second opinion on your reports? Send us a sample report and the list of services that send as your domain, and we will help you work out what to fix.
Further reading and sources
Frequently asked questions
What is a DMARC aggregate report?
It is an XML file, usually compressed, that a mailbox provider sends to the rua address in your DMARC record, normally once a day. It summarises the mail the provider saw claiming to be from your domain: the sending IP, how many messages, and whether SPF, DKIM and DMARC passed. It contains no message content.
Why am I not receiving DMARC reports?
Check that the rua address is correct and is written with the mailto: prefix, that the mailbox accepts large attachments, and that you have waited at least a day. If the report address is on a different domain, that domain must publish an authorisation record. Not every provider sends reports, and small domains may receive few.
What is the difference between rua and ruf?
The rua tag requests aggregate reports, which are summaries. The ruf tag requests forensic or failure reports about individual failed messages. Most large providers do not send forensic reports, because they can contain personal data, so plan around aggregate reports.
Can I read DMARC reports without a tool?
Yes for a handful of files, because they are plain XML. For anything beyond that, use a report processing service or a short script to total the results by source, because even a modest domain receives dozens of reports a day.
What does an alignment failure mean?
DMARC passes only when SPF or DKIM passes and the domain it authenticated matches the visible From domain. If a source passes SPF for the service provider domain but your From domain is different, DMARC fails even though SPF passed. The fix is to authenticate with your own domain, using a custom Return-Path or a DKIM signature with your domain.
How long should I stay at p=none?
Long enough to see every legitimate sender, which is usually two to four weeks and should include a month-end cycle if you send monthly mail such as invoices. Staying at p=none forever protects nothing, so set a date to move on.
What does the pct tag do?
The pct tag applies your policy to only a percentage of failing messages, for example pct=25. It lets you roll out quarantine or reject gradually. Support is common but not universal, so treat it as a soft control and keep watching the reports.
Will p=reject break my email?
It will block any message that fails DMARC, which is the point. Legitimate mail breaks only when a real sender is not authenticated and aligned. That is why you collect reports first, fix every legitimate source and move in steps.
What about forwarded mail and mailing lists?
Forwarding often breaks SPF because the forwarder is not in your record, and lists may change the message and break DKIM. Signed DKIM that survives, and ARC headers added by the forwarder, help receivers decide. Expect a small tail of failures from forwarding even in a healthy setup.
Do subdomains need their own DMARC record?
A DMARC record at your main domain also covers subdomains unless you override it. The sp tag sets a policy for subdomains, and a record at a subdomain overrides both. Unused subdomains are a spoofing target, so a strict policy for them is a quick win.