DMARC p=reject is bouncing legitimate email: how to find and fix the gap
You flipped your DMARC policy to p=reject, and within a day the support tickets start: the CRM stopped delivering, invoices from the billing platform vanished, the newsletter went to spam or bounced outright. The instinct is to roll back to p=none and walk away from DMARC entirely. Do not. A reject policy bouncing real mail is not DMARC misbehaving; it is DMARC telling you a sending source was never properly authorized. The fix is to find that source, not to silence the alarm.
Why this happens
DMARC passes when a message is aligned: either SPF passes for the same domain as the visible From: address, or DKIM passes with a signature from that domain. One of the two is enough. A message fails DMARC only when both SPF and DKIM fail to align.
While your policy was p=none, those failures were invisible — the mail still delivered, and the failures only showed up in reports you probably were not reading. The moment you set p=reject, every unaligned source starts bouncing. The classic culprits:
- A third-party sender (CRM, helpdesk, billing, marketing platform) that sends as your domain but was never added to your SPF record or set up with DKIM.
- A SPF record that overflowed the 10-DNS-lookup limit, causing SPF to return PermError so it cannot align.
- DKIM that signs with a different domain (the vendor's, not yours) and therefore does not align even though it "passes."
- A forwarding path that breaks SPF, where you were relying on SPF alone with no DKIM to fall back on.
Find the source before you change anything
The answer is in your DMARC aggregate (RUA) reports. If you set up DMARC without a rua= address, add one now and wait a day for reports to arrive. These XML reports list every IP that sent mail claiming to be your domain, and whether each passed SPF and DKIM alignment.
Aggregate XML is unpleasant to read by hand. Paste a report into the DMARC report viewer to see, per source IP, exactly which messages failed alignment and why. The failing IPs map directly to the vendor or server you forgot to authorize. That is your gap.
Fix the gap, not the policy
For each failing legitimate source:
If it should send as your domain, authorize it properly. Add its SPF include and, better, set up DKIM signing with your domain so the signature aligns. DKIM is the more robust path because, unlike SPF, it survives forwarding. Build or check the record with the SPF generator and the DKIM generator.
If your SPF record exceeds 10 DNS lookups, it is returning PermError and cannot contribute to alignment. Flatten or consolidate includes — this has its own dedicated guide.
If a vendor only supports DKIM with their own domain, look for a custom-domain or CNAME-delegation option in their settings so the signing domain becomes yours. Most mature platforms offer this; it is the difference between aligned and not.
Roll forward safely next time
If you are not yet at p=reject on another domain, stage it. Run p=none with reporting for a few weeks and read the aggregate data until no legitimate source is failing. Then move to p=quarantine with a low pct, watch, and only then to p=reject at full coverage. The DMARC generator builds each policy string with the right reporting tags so you are never flying blind.
Once you have authorized the missing source, leave the policy at p=reject. That is the point of DMARC: an attacker spoofing your domain bounces too. To confirm your published record is well-formed before and after the change, run it through the DMARC generator to check yours.