Decay University · Part 5: Deliverability decay

Lesson 43 of 64

How DMARC drifts

DMARC rot is drift: policies that outlive the reality they matched, forgotten sp= and pct= tags, and report addresses that went dark years ago.

Last updated 19 July 2026

DMARC rots differently from SPF and DKIM. Those break in DNS: a record vanishes, a key goes stale, a lookup budget blows. A DMARC record usually stays syntactically perfect for years. What rots is the relationship between the policy and the mail it governs. The record still says what it said on the day everything aligned; the sending reality drifted away from it; and the reporting channel that was supposed to warn you about the gap went dark somewhere along the way. Drift, not breakage. It's harder to spot precisely because every individual piece still looks fine.

You know the machine from DMARC, explained: a TXT record at _dmarc.yourdomain.com, a policy that receivers apply when a message fails both aligned SPF and aligned DKIM, and aggregate reports flowing back to whatever address the rua= tag names. Five drift modes, in the order I see them.

The policy outlives the reality it matched

The classic sequence. Two years ago someone did the DMARC rollout properly: audited every sender, fixed alignment everywhere, walked the policy up p=none, p=quarantine, p=reject. On the day p=reject went live, it was true: everything sending as the domain aligned.

Then the company kept living. Eighteen months later, marketing signs up for a survey tool that sends "as you" and never gets aligned, because the person doing that onboarding wasn't at the company for the DMARC project and has never heard of it. Under p=reject, that tool's mail gets refused or quarantined from its very first send.

And here is the actual failure: nobody connects the two events. They're separated by eighteen months and, usually, a couple of job changes. The investigation happens entirely inside the new tool ("their deliverability must be bad"), support tickets get exchanged, the tool sometimes gets replaced by another tool that fails identically. The policy did exactly what it was told to do, to your own mail. What we see monitoring domains is that a strict policy is only as strong as the onboarding habit that keeps new senders aligned with it, and that habit leaves when the person who built it leaves.

Subdomain gaps: the coverage you assume

DMARC has an inheritance rule that almost nobody holds in their head. The sp= tag sets policy for subdomains; when it's absent, subdomains inherit the main p= value. Absence means inheritance, presence means whatever it says. Drift lives on both sides of that rule.

Side one: the forgotten escape hatch. During rollouts, teams often set sp=none so that unknown subdomain senders can't get hurt while the apex tightens. Prudent for a quarter, corrosive for years. The apex proudly enforces p=reject while every subdomain, including ones that don't exist yet, is policed by nothing. New subdomain senders spin up over the years and never get held to anything, so their misconfigurations never surface. Anyone spoofing billing.yourdomain.com enjoys the same freedom.

Side two: strict inheritance meeting a new subdomain sender. Branded sending domains commonly live on a subdomain (Klaviyo setups, for instance, often send from something like send.yourdomain.com). If that subdomain's authentication goes in wrong, the apex policy applies to it through inheritance, and the brand-new stream fails hard under a p=reject nobody re-examined, while the apex record sits untouched and technically correct.

Either way the record reads clean. The gap only exists relative to a subdomain inventory, and almost no one keeps a subdomain inventory.

The pct= dial nobody turned back

The pct= tag was designed for staged rollouts: apply the policy to a percentage of failing messages while you build confidence. p=reject; pct=25 was a sensible waypoint. As a permanent state, it's a policy that mostly doesn't apply.

Left in place, a "reject" record enforces on a quarter of failures. RFC 7489 adds a detail that makes the leftovers even softer: messages that fall outside the sample under a reject policy get quarantine applied instead, one step down. Two consequences follow. Spoofing mostly works, since three quarters of forged mail dodges the reject. And your own misconfigured streams partially deliver, which is arguably worse for diagnosis: a stream that fails 100% of the time gets found in a day, while a stream that folders intermittently gets blamed on content, send time, Mercury being in retrograde, anything but the sampling tag. Our policy-strength check flags a pct= below 100 as a quiet weakening for exactly this reason; it's one of those tags people stop seeing on a record they've read twenty times.

The radar goes dark: dead rua=

Aggregate reports are the only feedback loop DMARC has. Every drift mode above is visible in them: the unaligned new tool shows up as a failing source, the subdomain gap shows up as traffic you don't recognize, the sampling shows up in the policy fields. Reports are how you'd know. Which makes the rua= address the single most consequential thing on the record to let rot.

It rots in mundane ways. The address belonged to the engineer who set DMARC up in 2021, and the mailbox died with their account; reports have bounced into nothing since. Or the mailbox is alive and nobody has opened it in years, because raw aggregate reports are gzipped XML and reading them by hand is miserable (the how is in reading DMARC reports). A radar with no one at the screen is scrap metal with a power bill.

There's a subtler variant. Reports sent to a different domain than your own require the receiving side to publish an authorization record, so report generators can confirm the destination agreed to receive your reports. If that authorization disappears, generators simply stop sending. Nothing on your record changes; the stream just ends.

Pointing at a processor that forgot you

Most teams sensibly use a third-party DMARC report processor instead of raw XML: rua=mailto:yourdomain@some-processor.example, dashboards, charts. The drift mode is the subscription lapsing while the record lives on. Trials expire, the tool that bundled DMARC reporting gets cancelled, a card fails. The processor stops accepting or stops storing your reports, its authorization record for you may quietly vanish, and your DMARC record goes on referencing the arrangement for years. The record looks thoroughly professional. Operationally, it's a phone number for a disconnected line, and it fails in the most silent way possible: you don't even get bounces, just an absence of news that feels exactly like good news.

Reading your own record with fresh eyes

The counter to drift is rereading, since every one of these modes survives a glance and dies under an actual read. Pull up your record and interrogate each tag against today: does p= match what your current senders can survive, does sp= still deserve its exception, is pct= at 100, does a human or a live processor actually receive what rua= names? The free health check reads all of it on your domain right now and flags the weakenings; it takes about a minute, which is a fair price for finding out your radar has been off since 2023.

Everything so far rotted inside records you own. The breakage in decay you don't control arrives from outside instead: provider rule changes, vendor migrations, and lists that age on their own.

Terms from this lesson

  • policy drift - a DMARC policy that was correct when published but no longer matches the current fleet of senders, typically after new tools arrive unaligned.
  • sp= tag - the policy applied to subdomains. When absent, subdomains inherit the main p= policy; a forgotten sp=none exempts them all.
  • pct= tag - the percentage of failing messages the policy applies to. A leftover rollout value like pct=25 leaves a reject policy mostly unenforced.
  • rua= tag - the address aggregate reports are sent to. If it points at a dead mailbox or a lapsed processor, DMARC's only feedback loop is gone.
  • aggregate report - the periodic XML summary receivers send about mail claiming to be your domain: which sources passed, failed, and aligned.
  • external destination authorization - the record a third-party report destination publishes to confirm it accepts your reports. Without it, generators stop sending.

Check yourself

1. A domain enforced p=reject successfully for two years. A newly added survey tool's mail is now being refused. What drifted?

2. A record reads v=DMARC1; p=reject; sp=none. What does the sp tag mean for subdomains?

3. What does a leftover pct=25 do to a p=reject policy?

4. Why is a dead rua= address arguably the worst DMARC rot of all?