What the three policies tell receivers

A DMARC record is a TXT record at _dmarc. plus your domain:

$ dig +short TXT _dmarc.example.com
"v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@example.com"

The p= tag tells receiving mail servers what you want done with mail that claims to be from your domain but fails DMARC:

  • p=none: do nothing special. Deliver it, or filter it, the way you would anyway, and send me reports. This is monitoring only.
  • p=quarantine: treat it as suspicious. In practice that usually means the spam or junk folder.
  • p=reject: refuse it. The receiving server rejects the message during the SMTP conversation, so the sending server gets a bounce. Gmail’s rejection uses a 5.7.26 code that mentions the domain’s DMARC policy; Outlook.com uses 5.7.509.

Two points people miss.

First, the policy only touches mail that fails. Mail that passes DMARC is unaffected whatever p= says. So the real question is never “which policy is best” but “how much of my legitimate mail fails right now”. If the answer is none, reject costs you nothing. If it’s some, reject bounces that mail.

Second, it’s a request. RFC 7489 lets receivers apply their own local policy, and they do. A receiver can still deliver mail you asked to reject, or junk mail that passed. Treat DMARC as a strong signal you send, not a switch you control.

What “fails DMARC” actually means: alignment

This is where most confusion comes from. DMARC doesn’t introduce a new check. It looks at SPF and DKIM results and asks whether they are for the same domain the recipient sees in the From: header. That’s called alignment.

A message passes DMARC if at least one of these is true:

  • SPF passes and is aligned: the domain in the envelope sender (the Return-Path, also called MAIL FROM) matches the From: domain.
  • DKIM passes and is aligned: the d= domain in a valid DKIM signature matches the From: domain.

Only one needs to hold. The classic failure is a newsletter or helpdesk service that sends as news@example.com but uses its own bounce domain and signs with its own DKIM key. SPF and DKIM both pass, for the service’s domain, and DMARC still fails. You can see it in the receiving side’s Authentication-Results header (Gmail’s format shown):

Authentication-Results: mx.google.com;
       dkim=pass header.i=@esp-mailer.example header.s=k1;
       spf=pass (google.com: domain of bounces+8812@esp-mailer.example designates 198.51.100.23 as permitted sender) smtp.mailfrom=bounces+8812@esp-mailer.example;
       dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=example.com

The fix is on the service’s side, in its domain settings: most services let you set up DKIM signing with your own domain (they give you CNAME or TXT records to add under _domainkey.example.com) and a custom bounce domain such as bounce.example.com. DKIM alignment is the one to get right. SPF breaks whenever mail is forwarded, because the forwarding server’s IP isn’t in your SPF record. DKIM survives forwarding as long as nobody modifies the signed content; mailing lists that rewrite the subject or append a footer are the usual exception.

Relaxed vs strict alignment

adkim= and aspf= control how closely the domains must match. Both default to r (relaxed).

  • Relaxed: the organizational domains must match. bounce.example.com aligns with example.com.
  • Strict (s): the domains must be identical. bounce.example.com does not align with example.com.

Keep relaxed unless you have a concrete reason. Strict alignment breaks the very common setup where a service uses a subdomain of yours for bounces or signing. What it protects against is a subdomain you’ve handed to someone else (a vendor who controls promo.example.com’s DNS, say), which most organisations either don’t have or can handle with that subdomain’s own DMARC record.

The other tags that matter

TagWhat it doesNotes
rua=mailto:…Where aggregate reports goThe data you need for the whole rollout. Set it from day one
ruf=mailto:…Where per-message failure reports goMany large mailbox providers don’t send these at all, for privacy reasons. Optional
pct=Percentage of failing mail the policy applies toDefault 100. Mail outside the sample gets the next lower policy: reject becomes quarantine, quarantine becomes none
sp=Policy for subdomainsIf absent, subdomains inherit p=. A subdomain with its own _dmarc record uses that record instead
adkim=, aspf=Alignment mode for DKIM and SPFr (default) or s
fo=When to generate failure reportsOnly matters with ruf. fo=1 asks for a report when either SPF or DKIM fails

A few rules that trip people up:

  • v=DMARC1 must come first in the record.
  • Publish one DMARC record. If a receiver finds two TXT records starting with v=DMARC1 at _dmarc.example.com, it applies no DMARC at all.
  • If rua points to a mailbox in a different domain, that domain has to agree to receive the reports, with a TXT record like example.com._report._dmarc.reports.example.net containing v=DMARC1. Hosted report services set this up for you. If you send reports to your own other domain, you have to add it yourself, or receivers will skip the address.

Reading aggregate reports before you move

Aggregate reports are XML files, usually zipped or gzipped and attached to an email, typically one per receiving organisation per day. Each record row says: from this IP, this many messages claimed to be from your domain, here’s how SPF and DKIM came out.

<record>
  <row>
    <source_ip>198.51.100.23</source_ip>
    <count>412</count>
    <policy_evaluated>
      <disposition>none</disposition>
      <dkim>fail</dkim>
      <spf>fail</spf>
    </policy_evaluated>
  </row>
  <identifiers>
    <header_from>example.com</header_from>
  </identifiers>
  <auth_results>
    <dkim>
      <domain>esp-mailer.example</domain>
      <selector>k1</selector>
      <result>pass</result>
    </dkim>
    <spf>
      <domain>esp-mailer.example</domain>
      <result>pass</result>
    </spf>
  </auth_results>
</record>

Read it as two layers. auth_results shows raw SPF and DKIM: both passed. policy_evaluated shows the DMARC view, which only counts aligned results: both failed, because the domain was esp-mailer.example, not example.com. disposition is what the receiver did, none here because the policy was p=none. Under reject, these 412 messages would have bounced. This is the same service as in the header example above, and it’s exactly what the reports are for.

Raw XML gets unreadable quickly. Use a report service or an open-source parser such as parsedmarc to aggregate them, then sort every sending source into one of three groups:

  1. Yours, passing with alignment. Your main mail platform, usually. Nothing to do.
  2. Yours, failing. A CRM, billing system, ticketing tool, survey tool, a printer that emails scans, a web server sending password resets. Each one needs aligned DKIM (preferred) or aligned SPF before you enforce.
  3. Not yours. Spoofing, or forwarding. Forwarded mail typically shows SPF failing but DKIM passing aligned, so it still passes DMARC. Spoofing fails both, and that’s the mail you want quarantine and reject to stop.

You’re ready to move when group 2 is empty for a full cycle of your business, including senders that only send monthly or quarterly. Don’t judge by total pass rate. A 99% pass rate where the 1% is your payroll notices is not ready.

A rollout that doesn’t lose mail

1. Publish p=none with rua. Check that the record parses and that SPF and DKIM are found with the email check.

v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com

2. Fix every legitimate source. Turn on custom-domain DKIM in each service. Add services to SPF only where they need it, and watch the 10-lookup limit while you do (SPF PermError guide). If a DKIM signature fails rather than mis-aligns, the DKIM failure guide covers why.

3. Move to p=quarantine. If you want a gradual ramp, use pct: p=quarantine; pct=25, then 50, then 100, watching reports and your helpdesk at each step. Treat pct as a rough dial rather than an exact percentage; how precisely each receiver samples is up to the receiver.

4. Move to p=reject. Keep rua forever. New services get added by other teams without telling you, and the reports are how you find out.

During the rollout, keep the TTL on the _dmarc record modest (an hour is reasonable). If something legitimate starts bouncing, you want a rollback to quarantine or none to reach receivers quickly. Then fix that sender and step up again.

Subdomains and domains that never send mail

sp= lets you lock down subdomains separately. If nothing sends from subdomains, sp=reject can go in early, even while p= is still at none. If a subdomain does send (say news.example.com for a newsletter service), give it its own _dmarc.news.example.com record so its rollout doesn’t hold up the main domain.

For domains that never send mail at all, such as parked domains and defensive registrations, skip the staging. Publish reject from day one, along with an SPF record that allows nothing and a null MX (RFC 7505) that says the domain receives no mail:

parked-example.com.          IN  MX   0 .
parked-example.com.          IN  TXT  "v=spf1 -all"
_dmarc.parked-example.com.   IN  TXT  "v=DMARC1; p=reject"

Why scanners flag p=none

“DMARC quarantine/reject policy not enabled” and similar findings from security scanners and vendor questionnaires all mean the same thing: your record exists but is at p=none, or there is no record. They’re right that p=none doesn’t stop anyone from sending mail as your domain.

p=none is still a legitimate place to be for a while. Gmail and Yahoo’s bulk-sender requirements, in force since February 2024, ask for a DMARC record and accept p=none. But none is meant as a stage, not a destination. BIMI, the standard for showing your logo in inboxes, requires an enforced policy, and so do most of the scanners and questionnaires that will keep asking.

If you’re answering a questionnaire mid-rollout, say so: current policy, target policy, and when you expect to get there. That’s a better answer than flipping to reject to make the finding go away and finding out from customers which systems you forgot.

Checking where you are now

dig +short TXT _dmarc.example.com
dig +short TXT k1._domainkey.example.com    # replace k1 with your DKIM selector

The email check shows SPF, DKIM and DMARC for a domain together, including the current policy, and the DNS lookup shows the exact TXT record as published, which helps when a dashboard shows one thing and receivers see another. For the full picture of where SPF, DKIM and DMARC fit together, see the email deliverability guide.

Check your own domain now

Free, no sign-up. Runs the exact check this guide describes and shows what to fix.