A Published DMARC Record Isn't the Same as an Enforced One
"We have DMARC" usually means a record exists, not that anything is enforced. The gap between p=none and an actual policy, why SPF alone doesn't close it, and how to move without breaking mail.
"We have DMARC" is one of the most confidently wrong sentences in email security, and it's usually said in good faith. A record exists.dig TXT _dmarc.example.com returns something. Somewhere, a setup guide was followed and a box got checked. None of that means anything is actually being enforced — and the gap between those two states is exactly where spoofed mail keeps landing in real inboxes even after the record went in.
The record that does nothing
A DMARC record is a DNS TXT entry at _dmarc.example.com that tells receiving mail servers what to do with mail claiming to be from your domain that fails SPF or DKIM, and where to send reports about it. The policy tag, p=, is what actually instructs a receiver — and the correct starting value is p=none.
v=DMARC1; p=none; rua=mailto:dmarc@example.comRead that literally: p=none means do nothing differently. Mail that fails authentication is delivered exactly as it would be with no DMARC record at all. What you get instead of enforcement is rua=— aggregate reports, daily summaries of who is sending mail as your domain and whether it's passing. That's the entire value of p=none: visibility, not protection. A domain that publishes it and stops there has completed step one of a three-step rollout and stopped, which from the outside looks identical to never having started.
Why nobody moves past it
The honest reason p=none is so sticky is that the next step is genuinely risky. Moving to p=quarantine or p=rejectmeans every sender you haven't enumerated — the helpdesk platform, the invoicing tool, the marketing system, a contractor's mail client — starts failing silently. Nobody wants to be the person who moved a DNS record and broke the invoicing emails for a week. So the record sits at p=none indefinitely, reports go unread, and the domain is exactly as spoofable as it was before DMARC entered the conversation.
The fix isn't to skip straight to p=reject— it's to actually use the reports the record is already generating:
- Publish
p=nonewith a realrua=address and let reports accumulate for at least a week or two. - Read them. Confirm every legitimate sender — mail provider, helpdesk, marketing tool, invoicing system — is passing SPF or DKIM alignment.
- Move to
p=quarantineand watch for any drop in legitimate mail landing in inboxes. - Move to
p=rejectonce quarantine has run clean for a stretch. This is the actual goal state — the one that gives DMARC its enforcement value.
The full mechanics — the three policy stages, what a missing or malformed p= tag does (nothing, silently), and how DMARC alignment works with SPF and DKIM — are in the DMARC guide.
SPF has the same problem, one level down
SPF gets the same treatment DMARC does, for the same reason. A record exists, someone checked a box, and the qualifier at the end — the part that actually matters — quietly stays wrong for years.
v=spf1 include:_spf.google.com ~all~all (soft fail) marks unauthorized senders as suspicious; most receivers still deliver the mail, often to spam. -all (hard fail) tells them to reject it outright. ~all is the correct staging value while you confirm every legitimate sender — same logic as p=none — but a domain that never promotes it to -all is publishing an SPF record that provides essentially no protection, for the same reason a p=noneDMARC record doesn't: it describes senders without instructing anyone to act on the description.
Two SPF failure modes are specific to SPF and worth knowing before you go looking for them in your own DNS: publishing a second SPF record (RFC 7208 permits exactly one — a second one makes receivers treat SPF as broken and ignore it entirely), and approaching the 10-DNS-lookup limit, where every include:, a, mx, ptr, and exists mechanism counts and nested includes recurse. Both are covered, with the exact mechanics, in the SPF guide.
Checking your own domain
dig TXT _dmarc.example.com and dig TXT example.com(for SPF) will show you whether records exist. They won't tell you at a glance whether the policy actually does anything, which is the part that requires reading the tag values, not just confirming a response came back. Nivaronix's SPF & DMARC checker does that read for you — it reports the policy strength, not just the record's presence, as part of a free scan alongside DNSSEC, CAA, TLS, and HTTP security headers.
Related findings this post is describing in practice: DMARC Policy Is Monitoring Only (p=none), SPF Set to Soft Fail, and SPF Record Provides No Protection.