DMARCbis Readiness: How Many Domains Still Publish pct, rf, and ri?
Of the 1,786 unique domains in our September scan that publish a DMARC record, 828 (46.4%) still carry at least one tag that RFC 9989 removed: pct, rf, or ri. That sounds bad, but almost none of it matters. 653 of the 660 records with pct say pct=100, which never changed anything, and rf and ri were never acted on in a way you would notice. Only 7 domains (0.4%) have the setup that actually behaves differently under DMARCbis: an enforcing policy with pct below 100 and no t tag.
The new tags have barely been adopted. One domain publishes t (and it's t=n, the default), 3 publish psd, and 5 publish np.
What changed in RFC 9989
RFC 9989 was published in May 2026. It obsoletes RFC 7489 and RFC 9091, and it is Standards Track, where 7489 was Informational. For the full list of changes, see what changed in RFC 9989. Two changes matter for this scan:
pct,rf, andriare removed. They are gone from the tag list in §4.7, and their IANA registry status is "historic" (§9.3).v=DMARC1is unchanged, andsp,np,fo,rua, andrufall remain.tis new.t=yasks receivers to apply your policy one level softer:rejectis treated asquarantine, andquarantineasnone. It has no effect atp=none(§4.7).
Appendix A.6 explains why pct went away: in practice it was only reliable at 0 or 100. The RFC describes t=y and t=n as "meant to be analogous" to pct=0 and pct=100. It does not say a receiver should read pct=0 as t=y.
Methodology
- Dataset: the DMARCdrift adoption scan of 2,240 domains across 10 categories, run on September 1, 2026. The domain-level data is on the DMARC adoption research page.
- Duplicates: 75 domains appear in more than one category (amazon.com is in both the Fortune 100 and the Tranco Top 500), so the scan covers 2,160 unique domains. The overall numbers in this post count each domain once. The sector table counts a domain in every category it belongs to, because each category is read on its own.
- Denominator: 1,786 unique domains whose DMARC lookup returned a record starting with
v=DMARC1. No lookup returned a record that failed this check. - Tag detection: we parsed each raw TXT record and checked which tags are present. We did not use the scanner's parsed
pctfield, because it reports 100 when the tag is missing. - Script:
scripts/dmarc-adoption/dmarcbis-readiness.pyin our repo. Every number below is copied from its output.
The removed tags: 828 of 1,786
| Tag | Domains | Share of DMARC publishers |
|---|---|---|
| Any of the three | 828 | 46.4% |
pct (any value) |
660 | 37.0% |
pct=100 |
653 | 36.6% |
pct below 100 |
7 | 0.4% |
rf |
92 | 5.2% |
ri |
452 | 25.3% |
pct=100 is a no-op. It was the default in RFC 7489, so writing it out never changed anything. Under DMARCbis the tag is ignored, which leaves you with the same full policy you already had. It's leftover config: delete it the next time you edit the record.
rf and ri are ignored. rf picked a failure-report format, and RFC 7489 §6.3 defined only one value for it (afrf). ri requested a reporting interval, but the same section only required receivers to support daily reports and treated anything else as best effort. Dropping them changes nothing you would see.
The one case that matters: 7 domains
Under RFC 7489, p=reject; pct=50 asked receivers to reject half of failing mail and quarantine the rest (RFC 7489 §6.6.4). Under p=quarantine; pct=0, failing mail got normal handling.
A DMARCbis receiver ignores pct, so it only sees p=reject or p=quarantine and applies the full policy request. The record you published as a partial rollout becomes full enforcement. The receiver still makes the final handling decision (§5.4, §7.4), but the request it acts on is no longer the one you meant.
7 of 1,786 DMARC publishers (0.4%) are in this position: p=quarantine or p=reject, pct below 100, and no t tag. Six are at p=quarantine and one is at p=reject. One uses pct=0 and six use a value from 1 to 99. That is a small number. Most organizations that used pct for a staged rollout either finished it or never started one.
As of the September 1 scan, the seven were:
| Domain | Category | Policy | pct |
|---|---|---|---|
| marathonpetroleum.com | Fortune 100 | p=quarantine |
50 |
| qualys.com | Cybersecurity Vendors, Top 100 SaaS | p=reject |
50 |
| illinois.gov | State Governments | p=quarantine |
75 |
| rubiconproject.com | Tranco Top 500 | p=quarantine |
50 |
| samsungcloud.com | Tranco Top 500 | p=quarantine |
50 |
| vungle.com | Tranco Top 500 | p=quarantine |
5 |
| shopifysvc.com | Tranco Top 500 | p=quarantine |
0 |
None of these is a misconfiguration under the rules they were written for. They are staged rollouts whose meaning shifts as receivers move to DMARCbis. The biggest shift is p=quarantine; pct=0: a record that asked for no quarantine at all becomes a full quarantine request.
If you're using pct below 100 to stage a rollout, there are two fixes:
- Keep the rollout soft for both generations. Publish
t=y; pct=0together. RFC 7489 receivers ignore the unknownttag and honorpct=0. DMARCbis receivers ignorepctand honort=y. See the pct deprecation post for the staged approach. - Or finish the rollout. If your aggregate reports show clean alignment, remove
pctand enforce fully.
The new tags: 1 t, 3 psd, 5 np
t: one domain publishes it, ironscales.com, with t=n. That is the default, so it asks for exactly what the record would do without it. No domain in the scan publishes t=y.
psd: three domains publish it, and they show both intended uses. myshopify.com publishes psd=y, which is what a public suffix operator is supposed to do: myshopify.com is on the Public Suffix List, since every shop gets its own subdomain. berkeley.edu and arxiv.org publish psd=n. RFC 9989 §4.7 says that value means the record "is published for a domain that is not a PSD, but it is the Organizational Domain for itself and its subdomains."
np: five domains publish it, all as np=reject. np sets the policy for subdomains that don't exist. It started in RFC 9091, an experimental extension, and is now part of the core spec. Because it existed before DMARCbis, it's the one newly standard tag that some domains already use.
Policy distribution, for context
| Policy | Domains | Share |
|---|---|---|
p=reject |
1,470 | 82.3% |
p=quarantine |
161 | 9.0% |
p=none |
151 | 8.5% |
Missing or invalid p |
4 | 0.2% |
Federal .gov domains make up 1,111 of the scan's 1,865 DMARC entries, and 93.4% of them are at p=reject, which pulls the overall shares up. See the September adoption update for the per-category policy picture.
By sector
This table counts domain entries, so a domain in two categories appears in both rows. Some sectors have only 25 to 50 domains with DMARC, where one domain moves the share by 2 to 4 points. Read the raw counts, not only the percentages.
| Sector | With DMARC | Any removed tag | pct=100 |
pct below 100 |
t |
psd |
np |
|---|---|---|---|---|---|---|---|
| US Federal .gov | 1,111 | 564 (50.8%) | 436 | 0 | 0 | 0 | 2 |
| Tranco Top 500 | 342 | 140 (40.9%) | 126 | 4 | 0 | 2 | 2 |
| Top 100 SaaS | 100 | 49 (49.0%) | 42 | 1 | 0 | 0 | 0 |
| Fortune 100 | 99 | 38 (38.4%) | 24 | 1 | 0 | 0 | 0 |
| Top 50 Universities | 50 | 15 (30.0%) | 14 | 0 | 0 | 1 | 1 |
| State Governments | 44 | 16 (36.4%) | 8 | 1 | 0 | 0 | 0 |
| Cybersecurity Vendors | 40 | 14 (35.0%) | 11 | 1 | 1 | 0 | 0 |
| Major News Outlets | 29 | 14 (48.3%) | 14 | 0 | 0 | 0 | 0 |
| Top 25 US Banks | 25 | 7 (28.0%) | 2 | 0 | 0 | 0 | 0 |
| Hospital Systems | 25 | 4 (16.0%) | 4 | 0 | 0 | 0 | 0 |
Every pct below 100 in the scan sits on an enforcing policy, so the "pct below 100" column is also the risky count for each sector. Federal .gov has the highest share of leftover tags (half its records carry one) and none of the risky ones: its pct values are all 100.
Cleanup checklist
- Look up your record. Run
dig TXT _dmarc.yourdomain.com +short, or use the DMARC checker, which explains each tag in your record. pct=100: delete it. Nothing changes.rf=orri=: delete them. Nothing changes.pctbelow 100 withp=quarantineorp=reject: decide now. If you're still testing, publisht=y; pct=0together. If you're done testing, removepct.pctwithp=none: delete it. It had no effect atp=none.- Leave
v=DMARC1alone. There is no DMARC2 version string. - Keep
rua. Aggregate reports are how you find out whether the change broke anything. DMARCdrift reads them for you, along with any failure reports you receive, and alerts you when your published policy changes.
Check your DMARC record now to see which of these apply to you.
