Build1 publisher3 min readPublished
Deleting pct=25 from a DMARC record quadruples the mail your policy touches
RFC 9989 removed the pct tag on 19 May 2026, and a record still carrying pct=25 describes a staged rollout that conforming receivers no longer honour. The replacement, t=y, gives one testing step and no percentages.
The Engineer · Build desk

What happened
- DMARC moved onto the IETF Standards Track as RFC 9989 on 19 May 2026, replacing RFC 7489 and RFC 9091.
- The new specification removes the pct tag outright, and documents the decision in an appendix titled "Removal of the 'pct' Tag".
- Reporting moved into two companion documents, RFC 9990 for aggregate reports and RFC 9991 for per-message failure reports.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- exposure A domain owner reading pct=25 off their own record is out by a factor of four on how much failing mail the quarantine decision touches, and the record still reads like a staged rollout.
- constraint Anyone who planned to reach p=reject by raising a percentage now has to get the same confidence from a single testing step plus report reading.
- decision For domains whose users post to mailing lists, the spec puts the burden of justification on publishing p=reject at all, which makes quarantine the defensible place to stop.
- cost Aggregate reports are now the only place two silent failures appear, an ignored pct tag and an SPF permerror past ten lookups, so somebody has to own that feed.
An unknown tag in a DMARC record is ignored. A conforming receiver reading `v=DMARC1; p=quarantine; pct=25; rua=mailto:[email protected]` quarantines every message that fails authentication, because the specification no longer defines a pct tag for it to honour [4][5]. The record still says 25. DMARC carried the status Informational for the ten years before the move to the Standards Track, and records written against that older spec are still live [1][3].
The dev.to write-up that flagged the change states the edit case plainly. "Receivers that don't recognise the tag already treat the policy as applying to everything, and removing it just makes that explicit," the post says [7]. So deleting pct=25 is a no-op at those receivers and a genuine policy change at any that still honour the tag, and the post notes receivers read it inconsistently enough that the spec dropped it [4][6]. Either way the record quarantines all failing mail instead of a quarter of it [8]. Divide 100 by 25: the volume of failing mail exposed to that quarantine decision is four times what the number in the record implies [9]. The post's own comment on that: "It's nicer to be the person who decided it than the person who finds out from the helpdesk" [21].
The replacement is a t tag, for testing. With t=y a receiver handles mail one step below the published policy, so p=reject behaves as quarantine and p=quarantine behaves as none, while reports keep arriving [10]. That gives a rollout one intermediate step, and the percentage ramp is gone [11].
A lot of DMARC advice treats p=reject as the finish line. RFC 9989 Section 7.4 says "domains that host users who might post messages to mailing lists SHOULD NOT publish Domain Owner Assessment Policies of p=reject" [12]. Lists and forwarders relay and rewrite messages in ways that break the original authentication, so rejecting on failure bounces legitimate mail from your own users, and list software often responds to those bounces by unsubscribing them [13]. The post reads p=reject as a sound destination for a purely transactional domain [20]. On any domain with human senders I would stop at quarantine.
Two other changes bite on multi-level domains. Organizational domain discovery no longer uses the Public Suffix List, and RFC 9989 replaces it with a series of DNS queries the spec calls the DNS Tree Walk [14]. sp is ignored on records published below the organizational domain or public suffix level; if you set it on a subdomain and saw no effect, that is why [16]. np, carried over from RFC 9091, publishes a policy for subdomains that do not exist at all, and without it those names inherit sp, or failing that p [15].
The SPF side did not change and still catches people. RFC 7208 caps an evaluation at ten DNS-querying terms, and going over produces a permerror, a hard failure you will not see unless you read your reports [17]. Every `include:` pulls in whatever that provider has published, and the provider's own includes count against your ten, so three or four mainstream providers gets uncomfortably close [18]. There is also a recommended limit of two void lookups, meaning queries that come back empty or name something that does not exist [19].
What to watch
- Whether major receivers publish how they implement t=y, since the one-step-below behaviour only exists if they honour it.
- Whether DNS hosting panels and DMARC validators start flagging pct as removed instead of passing it as valid syntax.
- Whether the split of reporting into RFC 9990 and RFC 9991 changes what existing aggregate report parsers accept.