DMARC from p=none to p=reject, without breaking real mail
The safe path from a do-nothing DMARC record to full enforcement. Read the reports first, fix every legitimate sender, and ratchet the policy in stages instead of one risky jump.
A DMARC record at p=none does exactly one useful thing: it sends you reports. It blocks nothing. It protects nothing.1 We see domains that have sat at p=none for years, collecting reports nobody reads, under the comfortable illusion that "we have DMARC." It's the email-security equivalent of a smoke detector with the battery taken out.
Enforcement is the point. p=quarantine and p=reject are what actually stop someone spoofing your domain. Getting there without bouncing your own newsletters, invoices, and helpdesk mail is the whole skill. Here's the staged way to do it.
Why not just publish p=reject today?
Because you almost certainly have legitimate senders you've forgotten about. The marketing platform. The CRM. The accounting tool that mails invoices. The scanner on the office printer that emails PDFs to reception. Some of them send as your domain and some of them are not yet aligned under SPF or DKIM, and several you will meet for the first time in the reports, like distant relatives at a funeral.
Publish p=reject before you've found them, and DMARC does its job perfectly: it rejects them. Your invoices stop arriving. The first you hear of it is an angry phone call about an invoice that never arrived, and now you're debugging in production with the policy live and the finance team watching.
p=rejectis not the goal you rush to. It's the reward for having already found and fixed every legitimate sender. The reports are how you find them.
Stage one: publish p=none and actually read the reports
Start at p=none with a reporting address.2
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:[email protected]"
The rua= address is the important part. Without it, receivers send no aggregate reports at all.3 Receivers that do send them usually send one per UTC day4: XML files listing every source that sent mail as your domain, and whether each one passed SPF and DKIM with alignment.
These reports are XML, not built for human eyes; RFC 9989 recommends they be machine-parsed.5 Paste them into the DMARC report viewer and you get a readable table instead. What you're looking for is a complete inventory of your senders. Give it at least a full month so monthly senders, like an invoice run, show up. RFC 9989 warns it can take many months before you're sure you've found everything.6
Stage two: fix every legitimate sender
Now the work. For each legitimate source in the reports, you want it passing DMARC through an aligned, authenticated identifier. DMARC needs only one of the two to line up, though RFC 9989 asks for one and preferably both:7
- SPF, with the envelope sender's domain aligned to your
From:domain, or - DKIM, with the signing domain aligned to your
From:domain.
In practice DKIM is the one to lean on. Plain forwarding breaks SPF alignment8, while a DKIM signature can survive it if the message isn't changed.9 A mailing list that edits the message breaks DKIM too.10 Microsoft 365 and Google Workspace both document DKIM signing for your own domain11, and Microsoft 365 does not sign mail from a custom domain until you set it up.12 Do that, confirm the key is published with the DKIM checker, and watch that source flip to pass in the next batch of reports.
The trap here is the long tail. The printer. The one-off script on a server in the corner. These are exactly the sources you'll want to either route through an authenticated relay or deliberately decide to let fail. Which is fine, as long as it's a decision and not a surprise.
Stage three: ratchet to quarantine
When the reports show your real senders consistently passing, move to quarantine. Quarantine is the safety net: RFC 9989 defines it as the domain owner treating failing mail as suspicious but possibly valid, rather than refusing it.13 A sender you missed can land in junk instead of vanishing.
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]"
Live here for a couple of weeks and keep reading the reports. Anything still failing now is either a sender you missed or an actual spoofer. Both are things you want to see before the next step.
A word on pct. The old RFC 7489 let you apply a policy to a percentage of mail, like p=quarantine; pct=25, as a throttle.14 Don't build a rollout on it. RFC 9989, the DMARC standard published in May 2026, removes pct, because in practice it was usually not applied accurately for any value other than 0 or 100.15 Its partial replacement is t=y, a testing flag that asks receivers to apply one level below the stated policy: p=quarantine; t=y is treated as none.16 Using quarantine itself as the intermediate stage is the more durable approach.
Stage four: p=reject
Once quarantine has been quiet (your senders passing, only spoofers and forgotten sources failing) move to reject. Now a forged message is refused at the door by receivers that honour the policy, which is the protection you wanted all along. RFC 9989 still lets a receiver accept failing mail under reject.17
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:[email protected]"
Don't drop the rua= address when you reach reject. The reports are just as useful afterwards: they're how you spot a new sender being added by some team six months from now, before it starts failing silently.
What about subdomains?
The sp tag sets the policy for subdomains, and the gotcha is that subdomains inherit your p value unless you say otherwise.18 If marketing.example.com sends through a platform you haven't aligned, your shiny new p=reject will reject it too.
While you're still onboarding senders, an explicit sp=none lets you enforce the apex without breaking a subdomain you haven't finished with. Tighten it to match once that subdomain's senders are clean.
With no np tag, RFC 9989 applies sp to subdomains that don't exist as well, so sp=none drops those to none too.19 Set np to your apex policy to keep them covered. Check your senders first. A subdomain whose lookup returns NXDOMAIN counts as non-existent20. A sending subdomain with nothing published under it yet falls under np, not sp.
A real one: two years, thousands of staff, four bulk mailers
This is one of our clients, and it isn't a typical DMARC rollout.21 They were in disarray when we started. We had to consolidate, get the stakeholders involved, and lock things down so that people could no longer sign up for their own sending services, which they had been doing for a long time. It was a change-management project more than a DMARC one.
They went from no DMARC record to p=reject on several domains, and it took about two years. The IT manager was new and the company has thousands of staff. Every time we thought a domain was done, the reports showed another source, and we had to trace it to a department and then to the person in charge of it.
The reports turned up four bulk mailers (Mailchimp, SendGrid, Sendinblue, which is now Brevo22, and Constant Contact), ticketing systems, legacy PHP scripts and cron jobs on servers that ran their own SMTP, and between 35 and 40 WordPress sites sending notifications. The departments sat down together and chose the one bulk mailer that worked best for the whole company, not for one user, and the other three went. The server mail was consolidated onto a proper SMTP server. The WordPress sites were in various states of disarray, so they were updated, patched and secured on the way. It also dealt with things on those servers that could have become security issues, which had nothing to do with DMARC.
One thing did break. A domain was already on p=quarantine when a new source appeared in the reports: 2,000 emails, automatically junked. We dropped that domain back to p=none, fixed the bulk sender and went back to quarantine. That took a couple of days. A company-wide email went out to stop it happening again, and it didn't.
Every domain ended on p=reject. That includes the subdomains we added for sending so that bulk mail no longer came from the apex, which we did for reputation. They started with their own subdomain policy and ended on reject with the root.
Our take
DMARC enforcement is not hard. It's just patient. The mistake is treating p=reject as a setting to switch on, rather than the last step of an inventory you've already completed. The reports do the hard part for you, but only if you read them.
What to do
- Publish
p=nonewith arua=address and let reports accumulate for at least a month. Read them in the DMARC report viewer. - For every legitimate sender, set up aligned DKIM (preferably) or SPF, and confirm each one flips to pass in the DMARC report viewer.
- Move to
p=quarantine, setsp=noneif you're still onboarding subdomain senders, and watch another fortnight of reports. - Move to
p=rejectonly when the failures are all spoofers or known dead sources. Keep therua=address forever.
Sources checked
Each numbered marker in the text links to the source that supports it. Every source was read on 4 October 2026 and again on 20 October 2026; the client case comes from our own work and has no outside source.
- “discovered policies of "p=none" MUST NOT modify existing mail handling processes”. Source: RFC 9989, §5.4. ↩
- “For best results, Domain Owners usually start with "p=none" (see Section 5.1.5) with the "rua" tag containing a URI that references the mailbox created in the previous step”. Source: RFC 9989, §5.1.4. ↩
- “If the tag is not provided, Mail Receivers MUST NOT generate aggregate feedback reports for the domain”. Source: RFC 9989, §4.7. ↩
- “Typically, the reporting period will encompass a single UTC day, beginning at 0000UTC”. Source: RFC 9990, §3.1.1.4. ↩
- “While it is possible for a human to read aggregate reports, they are formatted in such a way that it is recommended that they be machine-parsed”. Source: RFC 9989, §5.1.5. ↩
- “Depending on its cadence for sending mail, it may take many months of consuming DMARC aggregate reports before a Domain Owner reaches the point where it is sure that it is properly authenticating all of its mail”. Source: RFC 9989, §5.1.7. ↩
- “Send email that produces at least one -- preferably two -- Authenticated Identifiers (Section 3.2.1) that align with the Author Domain”. Source: RFC 9989, §5.1. ↩
- “In both cases, SPF cannot yield relevant Authenticated Identifiers, and DKIM must be relied upon to produce results that are relevant to DMARC”. Source: RFC 7960, §2.2. ↩
- “When an Alias preserves message content and does not make significant header changes, DKIM signatures may remain valid”. Source: RFC 7960, §3.2.1. ↩
- “Modification of email content invalidates most DKIM signatures, and many message-forwarding systems modify email content”. Source: RFC 7960, §2.3. ↩
- “Set up DKIM by generating a public DKIM key and adding it to your domain”. Source: Google Workspace Help: Set up DKIM, read 4 October 2026. ↩
- “Currently, no DKIM signing occurs for outbound mail from custom domains”. Source: Microsoft Learn: Set up DKIM to sign mail from your cloud domain, read 4 October 2026. ↩
- “The Domain Owner considers such mail to be suspicious. It is possible the mail is valid, although the failure creates a significant concern”. Source: RFC 9989, §4.7. ↩
- “The intent of the tag was to provide Domain Owners with a method to gradually change their preferred Domain Owner Assessment Policy (the "p" tag) from "none" to "quarantine" or from "quarantine" to "reject" by requesting the stricter treatment for just a percentage of messages that produced DMARC results of "fail"”. Source: RFC 9989, §A.6. ↩
- “Operational experience showed that the "pct" tag was usually not accurately applied, unless the value specified was either 0 or 100 (the default)”. Source: RFC 9989, §A.6. ↩
- “if the policy is "quarantine" and the value of the "t" tag is "y", a policy of "none" will be applied to failing messages”. Source: RFC 9989, §4.7. ↩
- “Mail Receivers MAY choose to accept email that fails the DMARC validation check even if the published Domain Owner Assessment Policy is "reject"”. Source: RFC 9989, §5.4. ↩
- “The policy applies to the domain queried and to subdomains, unless the subdomain policy is explicitly described using the "sp" or "np" tags”. Source: RFC 9989, §4.7. ↩
- “If the "np" tag is absent, the policy specified by the "sp" tag (if the "sp" tag is present) or the policy specified by the "p" tag (if the "sp" tag is not present) MUST be applied for non-existent subdomains”. Source: RFC 9989, §4.7. ↩
- “if the response code received for a query for a domain name is NXDOMAIN, then the domain name and any possible subdomains do not exist”. Source: RFC 9989, §3.2.13. ↩
- From the author's own client work. No outside source. ↩
- “From Sendinblue to Brevo: Introducing our new name & brand”. Source: Brevo: From Sendinblue to Brevo, read 4 October 2026. ↩