Skip to content
couryo

Blog

DMARC p=none vs quarantine vs reject: a safe rollout

What p=none, p=quarantine and p=reject do, the sp, np, pct and t tags, how to read an aggregate report and when to move up without losing legitimate email.

Deliverability7 min read

View as Markdown

Someone on the team read that p=reject protects the brand, changed the DMARC record on a Friday, and by Monday the invoices from the billing system had stopped reaching customers. Nobody connected the two for days. DMARC is the best protection against people spoofing your domain, but raising the policy without reading the reports takes legitimate mail down with it. This guide walks through the safe path, based on the current rules.

What each policy does#

DMARC is a TXT record at _dmarc.yourdomain.com. It checks whether a message passed SPF or DKIM with a domain aligned to the From, and tells the receiver what to do when it didn't:

Policy What happens to failing mail What it's for
p=none nothing; delivery as usual monitoring and reports
p=quarantine treated as suspicious, usually sent to spam the middle step, still recoverable
p=reject refused at the door full protection against spoofing

Two common misunderstandings:

  • DMARC doesn't look at content. It only answers "is this message really from the From domain?". A legitimate, authenticated email can still land in spam for other reasons; a spoofed email can still arrive under p=none.
  • p=none already counts. Gmail and Yahoo require DMARC from senders above 5,000 messages a day, and p=none is accepted (Gmail's sender guidelines); Microsoft asks for at least p=none at Outlook.com (2025 announcement). Moving to reject is protection, not one of their requirements.

The tags that matter#

TXT at _dmarc.example.com
v=DMARC1; p=none; rua=mailto:dmarc@example.com; adkim=r; aspf=r
Tag What it does
p the domain's policy: none, quarantine or reject
rua where receivers send aggregate reports (XML, usually daily)
sp policy for existing subdomains (shop.example.com); without it, p applies
np policy for non-existent subdomains (anything.example.com); without it, sp or p applies
adkim, aspf alignment mode: r (relaxed, subdomains count as the same domain) or s (strict, exact match only)
pct applied the policy to a share of messages; removed from the spec in 2026 (see below)
t t=y asks receivers to apply one level below the published policy, for testing; the default is t=n

What changed in 2026: pct out, t in#

In May 2026, DMARC got a Standards Track specification from the IETF, RFC 9989, replacing RFC 7489 (which was only informational). Two changes affect your rollout:

  • The pct tag was removed. The RFC explains that, in practice, values other than 0 and 100 were never applied accurately, and each receiver did it differently.
  • A t (testing) tag was added. With t=y, receivers apply one level lower: p=quarantine; t=y is treated as none, and p=reject; t=y as quarantine. It's the successor to the old pct=0.

Receivers take time to change, and Google's recommended rollout guide still shows pct examples (verified on 10/20/2026). Since the spec says unknown tags must be ignored, adding t=y breaks nothing for receivers that don't know it yet. Just don't count on pct=10 enforcing on exactly 10% of your mail.

How to read an aggregate report#

Reports arrive at the rua address as XML (sometimes compressed). An excerpt in the RFC 9990 format:

Aggregate report (excerpt)
<policy_published>
  <domain>example.com</domain>
  <p>none</p>
</policy_published>
<record>
  <row>
    <source_ip>203.0.113.25</source_ip>
    <count>1840</count>
    <policy_evaluated>
      <disposition>none</disposition>
      <dkim>pass</dkim>
      <spf>pass</spf>
    </policy_evaluated>
  </row>
  <identifiers>
    <header_from>example.com</header_from>
  </identifiers>
  <auth_results>
    <dkim><domain>example.com</domain><selector>s1</selector><result>pass</result></dkim>
    <spf><domain>bounces.example.com</domain><result>pass</result></spf>
  </auth_results>
</record>
<record>
  <row>
    <source_ip>198.51.100.7</source_ip>
    <count>212</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>
    <spf><domain>mail.billing-vendor.example</domain><result>pass</result></spf>
  </auth_results>
</record>

How to read it:

  • source_ip and count: which server sent, and how many messages.
  • policy_evaluated: the aligned result, which is what DMARC uses. pass here means it passed and was aligned with the From.
  • auth_results: the raw result, with the signing domain or envelope domain.
  • disposition: what the receiver did with the message. Under p=none, nothing is blocked.

In the example, the first block is your sending service, all good. The second is the classic problem: 212 messages from a billing vendor, with SPF passing for the vendor's domain, not yours, and no DKIM. To DMARC that's a failure. Under p=reject, those 212 invoices would be refused.

Reading XML by hand every day doesn't scale. Use a tool that groups reports by source and shows who fails.

Step-by-step rollout#

1. Inventory. List everything that sends with your domain in the From: company mailboxes (Google Workspace, Microsoft 365), your app, your store, billing and invoicing, CRM, help desk, marketing platform. Each needs DKIM with your domain, or an envelope on a domain of yours.

2. p=none with rua. Publish it and collect. Google suggests at least a week; if you have monthly sends (invoices, statements, monthly reports), wait a full cycle so they show up.

3. Fix every failing source. For each IP with fail under policy_evaluated: find out who it is, set up DKIM with your domain in that service or move its envelope to a subdomain of yours. A source you don't recognize may be spoofing, which is exactly what reject will stop.

4. p=quarantine in test mode, then for real.

Test (applies none where RFC 9989 is in effect)
v=DMARC1; p=quarantine; t=y; rua=mailto:dmarc@example.com
Quarantine enforced
v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com

5. p=reject. Once quarantine runs with no legitimate source failing:

Reject
v=DMARC1; p=reject; rua=mailto:dmarc@example.com

When to move up#

Move up a level when, over the whole observation period:

  • every legitimate source shows an aligned pass;
  • the remaining failures come from sources you don't recognize (spoofing) or from forwarding;
  • no new service started sending without DKIM;
  • you know how to roll back quickly (see below).

Forwarding: when someone forwards your email, SPF breaks because the forwarding server isn't in your SPF record. DKIM usually survives. That's why every legitimate service should pass with aligned DKIM, not SPF alone. Microsoft also points to ARC as the mechanism that preserves authentication through forwarding and mailing lists.

Subdomains#

  • Without sp, subdomains inherit p. Move the root to reject and shop.example.com goes to reject too, unless it has its own _dmarc record.
  • A subdomain with its own record governs itself. _dmarc.marketing.example.com applies to marketing.example.com, and an sp tag published on a subdomain is ignored.
  • Roll out subdomains separately when each has a different sender. A common path: p=reject; sp=quarantine while subdomains are still being watched.
  • Use np=reject so made-up names (account-security.example.com) can't be used in phishing.
  • Domains that never send (the .net that only redirects to your .com): publish v=spf1 -all and v=DMARC1; p=reject; right away.

How to roll back if mail goes missing#

If legitimate email stops after a change, drop the policy one level (from reject to quarantine, or to p=none) and fix the source. The change only reaches everyone once the record's TTL expires, so a short TTL on _dmarc (a few minutes) helps during the rollout. Messages already rejected don't come back; the sender has to resend them.

Where Couryo fits#

In Couryo, each domain's DMARC starts at p=none with rua=mailto:reports@dmarc.couryo.com, and Couryo parses every report (XML, zip or gzip). The domain's DMARC tab shows sending sources, how many messages each sent and whether they passed SPF, DKIM and DMARC, with a "someone is sending as you without authenticating" alert when a source fails. The deliverability agent only recommends moving up when the domain has had its current policy for 30 days, at least 99% of messages passed DMARC and no source failed, and it hands you the new record ready to copy. You change the record yourself: the agent reads and recommends, it doesn't touch your DNS. See Deliverability agent and Domains and DNS.

FAQ#

How long should I stay at p=none?#

Google suggests at least a week of reports. In practice, wait for at least one full cycle of your sending: if invoices go out monthly, they only appear in reports after the first run. Couryo's agent waits for 30 clean days before recommending a move.

Does p=quarantine send all my email to spam?#

No. Only messages that fail DMARC (no aligned SPF or DKIM). Legitimate, authenticated mail is delivered as usual. The risk is legitimate sources you haven't configured yet, which is why the reports come first.

Can I still use pct=25 to ramp up?#

You can publish it, but don't rely on it. RFC 9989 removed pct in 2026 because values other than 0 and 100 were never applied consistently. To test a policy without enforcing it, use t=y; to enforce, move from one level to the next.

Does DMARC alone keep my email out of spam?#

No. It proves the message comes from your domain, which the big providers require and which helps reputation. Complaints, bad lists and scam-like content still send mail to spam. See Why your emails go to spam.

Do I need p=reject to meet Gmail's and Microsoft's rules?#

No. Gmail, Yahoo and Microsoft accept p=none for bulk senders. p=reject is about protecting your domain from spoofing, and it's worth getting there carefully.