The short answer

Most SPF and DMARC problems come from a short list of mistakes: two SPF records instead of one, an SPF record that needs more than ten DNS lookups, an all mechanism that allows everyone, a DMARC record at the wrong name, and a DMARC policy left at p=none long after the reports are clean. Each one either breaks authentication outright or leaves the domain open to spoofing.

$ dig +short TXT example.com

$ dig +short TXT _dmarc.example.com

SPF lives at the domain itself, among its other TXT records. DMARC lives at _dmarc under the domain. For how the three standards fit together, see Email Phishing Protection: SPF, DKIM and DMARC.

SPF mistakes

MistakeWhat happensFix
Two TXT records starting v=spf1SPF evaluation returns permerror, which many receivers treat as a failureMerge them into one record
More than 10 DNS-querying terms (include, a, mx, ptr, exists, redirect), counting nested includespermerrorRemove services you no longer use, replace a and mx with ip4/ip6 where stable, or send some mail from a subdomain with its own record
Exceeding the receiver’s void-lookup limit (two is the recommended, configurable default)permerrorRemove includes of domains that no longer publish SPF
+all, or all with no qualifierEvery server in the world passes SPF for your domainEnd with -all or ~all
Using ptrSlow and unreliable; RFC 7208 says not to use itList the addresses or includes instead
Expecting SPF to protect the visible From addressSPF checks the envelope sender (Return-Path), which the recipient does not seeUse DMARC, which ties the result to the From domain

DMARC mistakes

DMARC is now defined by RFC 9989, published in 2026, which replaced RFC 7489. It changed a few details, so older guides can be out of date.

MistakeWhat happensFix
Record published at the domain instead of _dmarc.example.comReceivers do not find a policyMove it to _dmarc
More than one DMARC record at _dmarcReceivers treat the domain as having no policyKeep one
p=none with no rua addressNo requested DMARC enforcement and no aggregate report destination; the receiver still applies local policyAdd rua=mailto:..., read the reports, then move to quarantine or reject
p=none left in place indefinitelyDMARC requests no enforcement; delivery still depends on receiver policyFix the legitimate senders the reports show, then enforce
Relying on pct for a gradual rolloutRFC 9989 removed pct; receivers that follow it ignore the tagUse t=y (test mode) while you prepare to enforce
Reports sent to another domain that has not agreed to receive themReceivers drop the reportsThe receiving domain must publish a v=DMARC1 TXT record at example.com._report._dmarc.their-domain.example (RFC 9990, section 4)
Third-party senders that do not alignTheir mail fails DMARC once you enforceHave each one sign with DKIM for your domain, or use a custom return-path under your domain

Enforcing DMARC on a domain whose users post to mailing lists has a known side effect: lists that rewrite messages break DKIM, so the posts can be rejected. RFC 9989 advises that domains used by people on such lists should not publish p=reject.

Checking a record by hand

CommandWhat to look for
dig +short TXT example.comExactly one SPF TXT record after concatenating the character-strings within each record. Evaluate the whole policy and lookup limits: v=spf1 redirect=_spf.example.net can be valid without an all mechanism when the redirect target publishes a valid policy
dig +short TXT _spf.provider.exampleRepeat for each include to count lookups
dig +short TXT _dmarc.example.comOne record starting v=DMARC1, with p= and rua=

The most reliable test is a real message: send one to a mailbox you control and read the Authentication-Results header, which shows the SPF, DKIM and DMARC results and the domains each one checked.

How DNS Panopticon helps

Domain Visualizer reports a missing SPF record, more than one SPF record, an SPF record that allows all senders, a missing DMARC record, and the DMARC policy level (none, quarantine or reject), each with the record it is based on. It does not count SPF lookups or follow includes, and it does not read DMARC reports, so use the checks above for those.

Sources and further reading