Deploying DMARC with Monitoring and Enforcement
DMARC ties your existing authentication together and tells the world’s mailbox providers what to do when a message claiming to be from your domain fails it. This guide walks the full rollout: publish a monitoring-only _dmarc TXT record, read the aggregate reports for a few weeks, fix every legitimate source that fails, then ramp the enforcement percentage until you can safely set p=reject. After reading this you will be able to author a correct _dmarc record, interpret RUA XML, and move from observation to enforcement without bouncing your own mail.
Key objectives:
- Author a
_dmarcTXT record and understand every tag:p,sp,rua,ruf,pct,adkim,aspf. - Stand up aggregate (RUA) reporting and read the XML to find unauthenticated senders.
- Drive identifier alignment between the visible From domain and your SPF and DKIM results.
- Ramp safely from
p=nonetop=quarantinetop=rejectusingpctas a throttle.
How DMARC depends on SPF and DKIM
DMARC is not a third authentication method. It is a policy layer that reuses the results of SPF and DKIM and adds one new requirement: alignment. A message passes DMARC when at least one of the underlying checks both passes and aligns with the domain in the visible From: header.
- SPF alignment compares the
From:domain to the domain in the SMTP envelopeMAIL FROM(the Return-Path). Configure your sending sources correctly first by configuring SPF records to prevent spoofing. - DKIM alignment compares the
From:domain to thed=domain in the DKIM signature. Make sure every legitimate stream is signed by setting up DKIM signing for your domain.
If neither SPF nor DKIM aligns, DMARC fails and your policy decides the fate of the message. This is why you never start at p=reject: you must first discover which legitimate senders are not yet aligned.
The _dmarc TXT record and its tags
DMARC lives in a single TXT record at _dmarc.example.com. Here is a fully-loaded record with every tag this guide uses:
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=none; sp=none; rua=mailto:[email protected]; ruf=mailto:[email protected]; pct=100; adkim=r; aspf=r; fo=1"
| Tag | Meaning | Typical values |
|---|---|---|
v |
Version, always first | DMARC1 |
p |
Policy for the organizational domain | none, quarantine, reject |
sp |
Policy for subdomains; inherits p if absent |
none, quarantine, reject |
rua |
Address for aggregate (daily XML) reports | mailto: URI |
ruf |
Address for forensic (per-failure) reports | mailto: URI |
pct |
Percent of failing mail the policy applies to | 0-100 |
adkim |
DKIM alignment mode | r relaxed, s strict |
aspf |
SPF alignment mode | r relaxed, s strict |
fo |
Forensic report options | 0, 1, d, s |
Relaxed alignment (r, the default) lets mail.example.com align with example.com. Strict alignment (s) demands an exact domain match. Start relaxed; tighten only if you have a specific reason. The pct tag is your safety valve: at pct=25 with p=quarantine, only a quarter of failing messages are quarantined and the rest fall back to the next-weaker policy.
Prerequisites and environment setup
You need authority to edit the zone’s TXT records (registrar dashboard, hosted DNS, or an API token) and a place to receive reports. Tools used below:
dig9.16+ for verification.- A mailbox or DMARC analytics endpoint for the
ruaaddress. Raw XML is gzipped and tedious; most teams pointruaat a parsing service or ingest it into their own pipeline.
If the report mailbox is on a different domain than the one being protected, that provider must publish an authorization record. For reports about example.com sent to [email protected], the vendor publishes:
example.com._report._dmarc.reports.vendor.net. IN TXT "v=DMARC1"
Hosted vendors handle this for you; note it if you self-host the report inbox.
Step-by-step rollout
Step 1: Publish p=none with aggregate reporting
Start in pure observation mode. Nothing changes for your recipients; you simply begin collecting data.
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=none; rua=mailto:[email protected]; adkim=r; aspf=r; fo=1"
Keep the TTL modest (3600s) so corrections propagate quickly during the campaign; if you want to understand the trade-offs, see mastering TTL strategies. The fo=1 tag asks for a forensic report whenever any underlying check fails alignment, which surfaces problems faster.
Expected side effect: within 24-72 hours, mailbox providers begin emailing daily aggregate reports to your rua address. No mail is affected.
Step 2: Analyze aggregate reports for two-plus weeks
Each RUA report is a gzipped XML document summarizing one provider’s view of one day. The core of every record looks like this:
<record>
<row>
<source_ip>198.51.100.24</source_ip>
<count>42</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>fail</dkim>
<spf>pass</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>example.com</header_from>
</identifiers>
<auth_results>
<spf><domain>mailinglist.example</domain><result>pass</result></spf>
</auth_results>
</record>
Read it source by source. For each source_ip ask: is this a sender I recognize, and does it show dkim=pass or spf=pass with alignment? In the example above SPF passed but against mailinglist.example, not example.com, so it does not align and the message fails DMARC. Build an inventory: every marketing platform, ticketing system, CI notification service, and transactional provider that legitimately sends as your domain. Two full weeks captures weekly and monthly send cycles; do not rush this.
Step 3: Fix every failing legitimate source
For each legitimate source that fails alignment, fix it at the source rather than weakening DMARC:
- Missing DKIM: enable the provider’s DKIM signing and publish their selector record. Aligned DKIM is the most durable fix because it survives forwarding.
- SPF not aligned: make the provider use a Return-Path subdomain of your domain (custom bounce/return-path), or rely on DKIM alignment instead.
- Subdomain mail: if a subdomain like
t.example.comsends transactional mail, give it its own aligned setup rather than loosening the parent policy.
Re-check reports after each change. Your goal before advancing is simple: 100% of mail volume you recognize shows DMARC pass, and the only failures left are spoofers or noise you are happy to block.
Step 4: Move to quarantine and ramp pct
Once legitimate volume is clean, switch the policy to quarantine but apply it to only a slice of failing mail using pct. This limits blast radius while you watch for any source you missed.
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=quarantine; pct=25; rua=mailto:[email protected]; adkim=r; aspf=r"
Hold for several days, confirm no new pass-rate drop, then raise pct in steps: 25, then 50, then 100. At pct=100; p=quarantine, every failing message lands in spam folders.
Expected side effect: failing messages (including residual spoofing) are now filtered to junk for the quarantined percentage. Legitimate aligned mail is untouched.
Step 5: Enforce with p=reject
When p=quarantine; pct=100 has run clean for a week or two, advance to outright rejection. Consider setting sp explicitly so subdomains inherit the same protection deliberately.
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=reject; sp=reject; rua=mailto:[email protected]; adkim=r; aspf=r"
At p=reject, receivers refuse unauthenticated mail at SMTP time, so spoofed messages never reach the recipient at all. This is the destination: maximum protection against domain abuse with full visibility retained through rua.
Verification
Confirm the record is live and well-formed across resolvers:
dig +short TXT _dmarc.example.com @1.1.1.1
dig +short TXT _dmarc.example.com @8.8.8.8
Expected output once p=reject is published:
"v=DMARC1; p=reject; sp=reject; rua=mailto:[email protected]; adkim=r; aspf=r"
If the two resolvers disagree, you are mid-propagation; the techniques in debugging DNS propagation delays across global resolvers apply. Then validate behavior with a real send. Mail a message from each production stream to an external mailbox and inspect the Authentication-Results header:
Authentication-Results: mx.google.com;
dkim=pass header.d=example.com;
spf=pass smtp.mailfrom=example.com;
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.com
dmarc=pass with header.from matching your domain confirms alignment under the active policy. Finally, watch the next day’s aggregate report: the disposition for your own IPs should be none (pass), while spoofers show reject.
Troubleshooting
Legitimate mail fails alignment after moving to reject. Pull the Authentication-Results header from a bounced or quarantined message. If dkim=pass but the d= domain differs from From:, you have a DKIM alignment gap rather than a signing failure. Switch the source to sign with your own domain, or add an aligned DKIM selector. Roll the policy back to p=quarantine; pct=50 while you fix it, then advance again.
Forwarded mail and mailing lists break. Forwarders rewrite messages and break the DKIM body hash, while traditional mailing lists change the Subject and add footers, breaking signatures and SPF alignment. DMARC cannot tell this apart from spoofing. The durable fix lives at the list operator: lists should rewrite the From: to their own domain (a common practice) so DMARC is evaluated against the list domain, not yours. You should not relax your policy to accommodate other people’s lists; instead confirm via reports that the affected volume is genuinely list traffic and accept it as a known, bounded cost of enforcement.
Aggregate reports never arrive. Re-check the rua syntax: it must be a full mailto: URI and the record must start with v=DMARC1; p=.... A misordered v tag invalidates the entire record. Confirm with dig +short TXT _dmarc.example.com that there is exactly one DMARC record; duplicate TXT records cause receivers to ignore the policy entirely.
Forensic (ruf) reports raise privacy concerns. Forensic reports can contain full message headers and sometimes body content of failing mail, including third-party messages that merely spoofed you. Many providers never send them, and they can leak personal data. If your compliance posture is strict, omit ruf entirely and rely on aggregate data, which contains only IPs and counts. If you keep ruf, ensure the receiving mailbox is access-controlled and retention-limited.
Subdomain mail is rejected unexpectedly. Without an sp tag, subdomains inherit p. A forgotten service on notify.example.com that was never aligned will start failing the moment you reach p=reject. Set sp=none temporarily to isolate the parent policy, fix the subdomain’s alignment, then restore sp=reject.
Frequently Asked Questions
How long should I stay at p=none before enforcing? At least two weeks so reports capture weekly and monthly send patterns, and longer if you have many sending services. Advance only when 100% of recognized mail shows DMARC pass.
Does p=reject improve my email deliverability? Indirectly. Enforcement stops others from spoofing your domain, which protects your sending reputation, and several inbox providers favor domains with enforced DMARC. It does not fix deliverability problems caused by bad list hygiene or content.
What is the difference between rua and ruf?
rua delivers daily aggregate XML summaries (IPs, counts, pass/fail) and is what you act on. ruf delivers per-message forensic reports with header and body detail; it is optional, rarely sent, and carries privacy risk.
Can I skip quarantine and jump straight to reject?
Technically yes, but it is risky. Quarantine with a rising pct gives you a reversible, low-blast-radius proving ground. Skip it only on a brand-new domain that has never sent mail.
Why does my mail still fail DMARC even though SPF passes?
SPF likely passes against your provider’s Return-Path domain, not your From: domain, so it does not align. Either align the Return-Path to a subdomain of yours or ensure aligned DKIM signing, which is the more robust path.
Related
- Configuring SPF Records to Prevent Spoofing
- Setting Up DKIM Signing for Your Domain
- Mastering TTL Strategies
- Debugging DNS Propagation Delays Across Global Resolvers
Back to Advanced SRV & MX Routing