The New DMARC Standard (RFC 9989): What Changed and What to Update

DNS query output for _dmarc.sh.consulting showing v=DMARC1; p=reject; np=reject; rua=mailto:sh@dmarc.sh; ruf=mailto:sh@dmarc.sh; fo=1:d:s with the new np=reject tag highlighted in purple. SH Consulting's production DMARC record deployed against the new RFC

DMARC just received its first major update since 2015. The protocol works the same way it did last week. But a few changes affect what should be in your record, and one of them is worth doing this week.

Screenshot of the IETF Datatracker page for RFC 9989, showing the document as a Proposed Standard published May 2026, obsoleting RFC 7489 and RFC 9091, authored by T. Herr (Valimail) and J. Levine (Standcore LLC).
RFC 9989 on the IETF Datatracker, published May 2026 as a Proposed Standard. It obsoletes RFC 7489 (the original DMARC specification from 2015) and RFC 9091 (the experimental PSD extension).

The IETF published RFC 9989 in May 2026, replacing RFC 7489 as the authoritative DMARC specification. The new document is a Proposed Standard, where the original was Informational — a meaningful upgrade in how strictly mailbox providers are expected to implement it.

Most of the changes are cleanup. The protocol still works on SPF and DKIM, the record still starts with v=DMARC1, the policy values are still none, quarantine, and reject. Existing records continue to work. What changed is the discovery mechanism that decides which record applies to a given message, a few tags that were added or removed, and the formal handling of interoperability problems that have been known issues for the past decade.

This post walks through what changed in the record format, what changed in how Mail Receivers find and apply your record, and what every Domain Owner should actually update.

What stays the same

Your existing DMARC record still works. RFC 9989 introduces no breaking changes. Mail Receivers implementing the new specification interpret existing records the same way receivers running on RFC 7489 do, with the exception of a few removed tags that are now silently ignored.

The fundamental DMARC mechanism is unchanged. A message passes DMARC if SPF or DKIM produces an aligned pass result. Alignment is still either relaxed (same Organizational Domain) or strict (identical). The Domain Owner Assessment Policy is still expressed in the p tag, with sp available for existing subdomains. Aggregate reporting still flows through the rua tag.

There is no urgent migration. There are, however, improvements worth making.

The new np tag

This is the most consequential addition for ordinary Domain Owners.

Under RFC 7489, the p tag covered the Organizational Domain, and the sp tag covered subdomains — but the specification did not clearly distinguish existing subdomains from subdomains that don't exist in DNS. Different Mail Receivers handled the gap differently, which left a real attack vector. An attacker could send mail from wire.example.com or payments.example.com — subdomains the Domain Owner never created — and receiver behavior was inconsistent.

RFC 9989 closes that gap. The new np tag specifies the Domain Owner Assessment Policy for non-existent subdomains of the Organizational Domain. Per Section 4.7, the policy expressed by this tag applies only to non-existent subdomains of the Organizational Domain queried — not to existing subdomains and not to the domain itself. If np is absent, Mail Receivers fall back to sp. If sp is also absent, they fall back to p.

The definition of "non-existent" comes from Section 3.2.13 and follows RFC 8020: if a DNS query returns NXDOMAIN, the domain and any possible subdomains do not exist.

np=reject is the cheapest spoofing protection in the entire update. Adding it costs nothing, requires no monitoring, and immediately closes off the common attack pattern of inventing plausible-sounding subdomains. It does not, however, do anything about existing subdomains being weaponized — that's a separate problem with its own mitigation path.

The psd tag — and why it matters even if you don't run a TLD

The psd tag is described in some early commentary as a tag only PSD operators need to think about. That undersells it.

Per Section 4.7, the psd tag has three values:

  • y — the domain is a Public Suffix Domain (used by PSOs)
  • n — the domain is not a PSD, but it is the Organizational Domain for itself and its subdomains
  • u — the default; the domain may or may not be the Organizational Domain, and Mail Receivers should run the DNS Tree Walk to find out

Every DMARC record without an explicit psd tag is implicitly psd=u. That means every Domain Owner is already opting into the tree-walk behavior — they just may not know it.

The interesting case for non-PSD Domain Owners is psd=n. Section 5.1.8 of the RFC walks through this: in large, complex organizations that delegate DNS management to local teams, psd=n lets a department declare a node in its subtree as the Organizational Domain. A department publishing a record at _dmarc.division.example.com with psd=n stops the tree walk there and becomes authoritative for itself and its subdomains, instead of inheriting policy and reporting URIs from the apex domain.

For most organizations with a flat domain structure — one company, one apex domain — leaving psd absent (implicit u) is correct. But for organizations that have inherited a fragmented DNS posture across business units, subsidiaries, or regional offices, psd=n at a deliberately chosen node is the new mechanism for asserting "policy and reporting stop here."

One caveat from Section 5.1.8 worth knowing: the tree walk has an eight-label cap built into it as anti-abuse protection. If your Author Domain has more than eight labels and you publish a psd=n record at an intermediate point, that intermediate record may never be queried — Mail Receivers will skip it. The RFC's recommendation is that long Author Domains MUST publish a DMARC Policy Record at their own location, because that record is always queried before the tree walk begins.

The DNS Tree Walk replaces the Public Suffix List

Section 4.10 introduces the most architecturally significant change in RFC 9989.

RFC 7489 relied on the Public Suffix List to determine the Organizational Domain for any given Author Domain. The PSL is a community-maintained file of TLD-like boundaries — co.uk, com.au, github.io, and so on. Different Mail Receivers used different versions of the list, updates lagged, and the RFC itself acknowledged that a more reliable method should replace it.

RFC 9989 replaces the PSL with the DNS Tree Walk. Instead of consulting an external list, the Mail Receiver walks up the DNS tree label by label and queries for a DMARC Policy Record at each step. The first record found that contains psd=n or psd=y ends the walk and determines the Organizational Domain. If no such record is found, the receiver selects the record with the fewest labels.

To prevent denial-of-service attacks via maliciously long Author Domains, Section 4.10 caps the tree walk at eight queries — equivalent to seven labels. Author Domains with more than eight labels get shortcut: the receiver removes labels until seven remain, then walks from there.

Side-by-side diagram showing two DMARC discovery walks under RFC 9989. The left walk starts from mail.division.example.com, climbs upward through DNS, and stops at division.example.com where a psd=n record is found. Reports flow to division-reports@example.com. The right walk starts from example.com itself and completes on the first lookup at the apex record, with reports flowing to apex-reports@example.com. In both cases, records in untraversed branches of the DNS tree are never queried.
Each message triggers its own upward walk from its Author Domain. The walk stops at the first record containing psd=n or psd=y. Records in other branches of the tree are not queried — each message resolves to exactly one DMARC record.

For domains with conventional structures — mail.example.com, support.example.com, and so on — the tree walk produces the same result the PSL did. The difference is reliability: every Mail Receiver running RFC 9989 walks the same tree against the same DNS, with no third-party list to fall out of sync.

What t=y actually does

The pct tag in RFC 7489 was a partial rollout knob: pct=10 meant "apply this policy to 10% of failing messages." In practice, only pct=0 and pct=100 (the default) produced consistent behavior across receivers, and values in between were unreliable.

RFC 9989 removes pct entirely and replaces it with t ("DMARC policy test mode"), which has two values:

  • t=y — request that Mail Receivers not apply the declared policy
  • t=n — the default; apply the policy as written

The exact behavior of t=y is defined in Section 4.7:

"if the policy is 'quarantine' and the value of the 't' tag is 'y', a policy of 'none' will be applied to failing messages; if the policy is 'reject' and the value of the 't' tag is 'y', a policy of 'quarantine' will be applied to failing messages."

The same section adds two important constraints. First, t has no effect on a p, sp, or np value of nonep=none; t=y is the same as p=none. Second, the tag does not affect the generation of DMARC reports. Receivers continue to send aggregate reports at the declared severity regardless of test-mode status.

t=y is the new mechanism for staged rollouts. Used with p=reject, it gets you quarantine-level enforcement while you finish vetting reports. Used with p=quarantine, it gets you monitoring-level behavior while keeping the declared policy visible to anyone inspecting the record.

This has a practical consequence for anyone following our guide on moving DMARC from p=none to p=reject: the gradual pct=10 → 25 → 50 → 100 rollout described there no longer applies under RFC 9989. The equivalent staged path now is p=quarantine; t=yp=quarantinep=reject; t=yp=reject. The methodology — authenticate every sender, monitor reports, advance only when you can account for all traffic — is unchanged. The tactical knob is different.

Tags that were removed

Three tags are gone in RFC 9989 (per Appendix C.5.2):

The pct tag has been removed entirely. Its function is taken over by t=y for the all-or-nothing case that actually worked in practice. Receivers conforming to the new RFC will silently ignore pct if they find it in a record. Removing it is good hygiene but not urgent.

The rf tag specified the report format. Only one format (afrf) was ever defined or used, so the tag served no purpose.

The ri tag specified a desired interval between aggregate reports. Section 5.3.8 of the new RFC instead recommends that Mail Receivers send aggregate reports at least every 24 hours, regardless of what ri requested. The tag is gone.

If your record contains any of these tags, they're no longer doing anything. Cleaning them up isn't urgent — receivers ignore unknown and removed tags per the formal definition — but it's good hygiene on the next update.

Is your DMARC record ready for RFC 9989?

Free 30-minute review against the new standard.

Book a 30-Minute Review

Policy is local — and now the RFC says so directly

Section 5.4 of RFC 9989 opens with a line that matters more than its understatement suggests:

"The final handling of any message is always a matter of local policy and is left to the discretion of the Mail Receiver."

This is consistent with how DMARC has always worked in practice. Section 1 reinforces it: a mail-receiving organization can choose to honor the requested handling, "but it is not required to do so." DMARC is one input into a larger filtering decision, and receivers may choose different actions entirely.

What's new in RFC 9989 isn't this idea — it's how clearly the document states it. The discretion that Mail Receivers exercise is now part of the normative text rather than implied.

We documented one specific instance of this in detail earlier this year. In a client environment where the published policy was p=reject, a phishing message reached the inbox carrying the headers dmarc=fail action=oreject and compauth=none reason=451 — Microsoft 365 silently overriding the policy and delivering anyway. The full analysis of how Microsoft 365 silently overrides DMARC p=reject as oreject covers what's actually happening: composite authentication is being skipped on a structural condition (a third-party gateway sitting in MX) that puts the tenant into a trusted-relay code path. The override doesn't appear in DMARC aggregate reports, which means a domain owner can sit at p=reject with every monitoring dashboard green and still have spoofed mail landing in user inboxes.

That post is the practical companion to Section 5.4. The RFC describes Mail Receiver discretion at the level of a protocol property. The oreject finding is what it looks like in production at the world's largest enterprise mail provider — with a real header as evidence. For Domain Owners, the practical effect of Section 5.4 is unchanged: p=reject dramatically reduces spoofing because the major Mail Receivers honor it, but it does not guarantee that any specific receiver will reject any specific message in any specific configuration.

Interoperability and mailing lists

Section 7.4 is the section the new RFC's authors point to as the part most people should read. It covers the long-standing interoperability problems caused by mailing lists, forwarders, and other intermediaries that modify messages in ways that break DMARC alignment.

The short version: mailing lists frequently modify a message's body or headers in ways that invalidate the original DKIM signature, and they typically use their own envelope sender, which breaks SPF alignment with the Author Domain. A p=reject policy on the Author Domain can cause mailing list traffic from that domain to be rejected by subscribers' receiving servers.

The new RFC does not resolve this — there is no perfect fix at the protocol level — but it does formalize the guidance. Section 5.1.7 directs Domain Owners considering enforcement to read Section 7.4 in detail, and Section 7.4 itself documents the tradeoffs without prescribing a specific policy choice.

The practical reading for Domain Owners is that p=reject remains the right policy for transactional senders, SaaS platforms, financial services, and any organization whose users don't typically post to listservs from their work address. For organizations whose employees actively participate in mailing lists from their corporate domain, p=quarantine is the more interoperable choice. np=reject can be added in either case — it applies only to non-existent subdomains, so it doesn't interact with the mailing list problem at all.

A record under RFC 9989

Here's what a clean, modern DMARC record looks like for a typical Domain Owner under RFC 9989:

v=DMARC1; p=reject; np=reject; rua=mailto:reports@example.com; ruf=mailto:reports@example.com; fo=1
DNS query output for _dmarc.sh.consulting showing a CNAME record pointing to dmarc-r.dmarc.cc, which resolves to the TXT record: v=DMARC1; p=reject; np=reject; rua=mailto:sh@dmarc.sh; ruf=mailto:sh@dmarc.sh; fo=1:d:s. The np=reject tag is highlighted.
The DMARC record for sh.consulting as of May 2026, queried directly from authoritative DNS. The np=reject tag — the central addition in RFC 9989 — is in place alongside p=reject and full aggregate and failure reporting. The CNAME delegation to dmarc-r.dmarc.cc is how we manage policy updates without touching the customer's apex DNS zone on every revision.

What's in it, and why:

  • v=DMARC1 — required, must be first
  • p=reject — enforcement policy for the Author Domain and existing subdomains
  • np=reject — explicit policy for non-existent subdomains, the new protection in RFC 9989
  • rua= — aggregate report destination
  • ruf= — failure report destination. Section 10.2 of RFC 9989 documents privacy concerns with failure reporting, and the major receivers have been inconsistent about sending them — but in our monitoring, failure reports continue to arrive at a useful enough volume to keep the tag in place. They're the only DMARC artifact that includes per-message detail, which is valuable for forensics on suspected spoofing. We leave ruf= published.
  • fo=1 — generate a failure report when any underlying authentication mechanism fails to produce an aligned pass result. Without this, the default fo=0 only triggers reports when all mechanisms fail, which misses partial failures that are useful to see

What's not in it, and why not:

  • No pct= — removed from the standard
  • No rf= or ri= — removed from the standard
  • No psd= — the implicit u default is correct for any Domain Owner who isn't a Public Suffix Operator and doesn't need to assert a non-default Organizational Domain boundary
  • No sp= — when omitted, the policy in p is applied to existing subdomains, which is the desired behavior for most domains

For organizations with mailing list exposure, swap p=reject for p=quarantine while keeping np=reject for the subdomain protection.

What to do this week

For most Domain Owners, three actions:

First, add np=reject to your DMARC record. This is the only meaningful new protection in RFC 9989, it closes a real spoofing vector, and it costs nothing. Mail from non-existent subdomains has no legitimate purpose for any organization we've encountered.

DMARC.cc validator showing sh.consulting checked in 0.17 seconds with DMARC valid, SPF soft fail, and policy at p=reject. The expanded DMARC record displays v=DMARC1; p=reject; np=reject; rua=mailto:sh@dmarc.sh; ruf=mailto:sh@dmarc.sh; fo=1:d:s with np=reject highlighted.
DMARC.cc validating the sh.consulting record against RFC 9989, including recognition of the new np=reject tag. Most legacy validators don't yet parse the new tags — you can check your own record at dmarc.cc to confirm it deploys cleanly under the new standard.

Second, remove any pct=, rf=, or ri= tags from your record. They've been removed from the standard. If you have ruf= published, leave it — failure reports continue to arrive in practice and remain useful for forensic detail on spoofing attempts.

Third, review your p value if your organization has users who post to mailing lists from their work domain. Section 7.4 of the RFC is the authoritative reference. For pure transactional senders, p=reject remains appropriate. For organizations with mailing list exposure, p=quarantine is more interoperable.

If you operate a Public Suffix Domain, you have a separate set of considerations in Section 5.2 — chiefly that any DMARC record you publish MUST include psd=y. If you operate a large organization with decentralized DNS management and want to designate an internal subtree as its own Organizational Domain, Section 5.1.8 covers the psd=n mechanism for doing that, along with the eight-label tree walk cap that constrains where it can be placed.

Beyond these three, the substantive work of DMARC hasn't changed. Authenticate every legitimate sender, monitor aggregate reports until you can account for all traffic, move to quarantine, confirm nothing breaks, then move to reject. RFC 9989 cleans up the protocol around that work — and the receiver-side caveat we've written about previously is now part of the normative text — but the work itself looks the same.

At SH Consulting we manage DMARC enforcement end-to-end — from initial authentication audit through monitoring, enforcement, and ongoing record maintenance as standards evolve. If you'd like us to review your current DMARC record against RFC 9989 and identify what should be updated, book a call.

Get the free Email Deliverability Guide

15 rules for reaching the inbox. Used by 450+ organizations.

Download the Guide