Email authentication
SPF PermError: What It Means and How to Fix It [2026]
TL;DR: permerror means a receiver tried to evaluate your SPF record and couldn't, because it is structurally invalid or blew past a hard limit. The three usual causes are more than 10 DNS-querying mechanisms, more than 2 void lookups, and syntax errors like publishing two SPF records on one domain. A permerror doesn't always bounce mail, but it removes SPF as a DMARC alignment path, so it is worth fixing the day you find it.
By Adam, DMARCit Last updated July 2026
What PermError actually means
SPF evaluation returns one of a fixed set of results, defined in RFC 7208 §2.6: pass, fail, softfail, neutral, none, temperror, and permerror. A permerror (§2.6.7) means the receiver could not process your record because it is malformed or exceeds a published processing limit. It is a permanent condition: the same record evaluated a second time produces the same error, because nothing transient is involved.
The distinction from temperror matters for diagnosis. A temperror is a transient DNS failure, a timeout or a SERVFAIL, and it may clear on its own or on the next delivery attempt. A permerror is structural. It will not fix itself, and every message from your domain that a receiver evaluates against the broken record hits the same wall until you change the record.
Crucially, permerror is not the same as fail. fail is SPF working correctly and telling the receiver "this sender is not authorized." permerror is SPF not working at all. The receiver never gets a clean yes-or-no, which is a different and in some ways worse position to be in, because you have lost the signal entirely rather than gotten a definitive negative.
Why PermError breaks DMARC, not just SPF
DMARC passes when at least one of SPF or DKIM both passes and aligns with the domain in the From: header. SPF can only contribute to that if it returns pass. A permerror is not a pass, so SPF drops out of the DMARC calculation completely. Your domain is now relying on DKIM alone to carry alignment.
That is survivable right up until it isn't. If your DKIM signing is solid and aligned, mail keeps passing DMARC on the DKIM path while SPF quietly throws permerror in the background, and you may not notice for months. Then a vendor rotates a DKIM key without telling you, or an internal flow starts sending unsigned, and suddenly the only authentication path you had left is gone too. Now mail is failing DMARC, and if you are at p=quarantine or p=reject, it is landing in spam or bouncing.
There is a second-order effect worth naming: some receivers treat an SPF permerror more harshly than a plain fail in their own spam scoring, independent of DMARC. So even for mail that still passes DMARC via DKIM, a broken SPF record can drag on deliverability. This is why "the mail is still getting through" is not a reason to leave a permerror in place. Fix it before you build anything on top of it, especially DMARC enforcement.
Cause 1: too many DNS lookups (the 10-lookup limit)
This is the most common cause by a wide margin. RFC 7208 §4.6.4 caps SPF evaluation at 10 DNS-querying mechanisms. Cross that ceiling and the receiver is required to return permerror and stop. The mechanisms that count toward the limit are include, a, mx, ptr, exists, and the redirect modifier. The ones that do not count are ip4, ip6, and all.
The trap is that the limit is recursive. A single include:_spf.google.com looks like one lookup, but that record contains its own nested includes, and every one of them counts against your budget of 10. Add Microsoft 365, a marketing platform, a helpdesk tool, and a transactional provider, and you can be at 14 or 15 effective lookups while your published record only shows five include: mechanisms. You blow the limit without ever seeing a long record.
This is why the count creeps up silently. Nobody adds an eleventh lookup on purpose. It happens when marketing signs up for a new SaaS tool and pastes in the vendor's recommended include:, or when an upstream provider quietly adds a nested include to their own record and pushes your total over the edge without you changing anything. The fix is an audit, and in the harder cases, SPF flattening.
Cause 2: void lookups (the 2-void limit)
Less well known, and easy to miss: RFC 7208 §4.6.4 also caps void lookups at 2. A void lookup is a DNS query made during SPF evaluation that returns an empty answer, either NXDOMAIN (the name doesn't exist) or a NOERROR response with no records of the type SPF asked for. Hit a third void lookup and the receiver returns permerror, even if your total lookup count is comfortably under 10.
The usual source is dead senders. You have an include: pointing at a service you stopped using, and the provider has since torn down that hostname, so the query returns NXDOMAIN. Or an a or mx mechanism references a subdomain that no longer resolves. Each of these is a void lookup, and a record can accumulate two or three of them over the years as vendors come and go, tipping into permerror for a reason that has nothing to do with the size of the record.
Void lookups are sneaky because they are invisible in a casual read of the record. The include: looks perfectly valid; it is only when you actually resolve it that you discover it points at nothing. This is why proper SPF validators resolve every mechanism rather than just counting them, and why "the record looks fine to me" is not a diagnosis.
Cause 3: syntax errors and malformed records
The third bucket is plain invalidity, and the single most common version is two SPF records on the same domain. RFC 7208 §3.2 is explicit that a domain must publish exactly one record starting with v=spf1. Two of them, often because someone added a second record for a new sender instead of merging into the existing one, is a permerror. The fix is to merge them into a single record, not to pick one.
Other syntax faults produce the same result: a malformed mechanism, an unknown modifier, a stray character, a macro expression that doesn't parse, or a mechanism with a bad CIDR like ip4:192.0.2.0/33. The deprecated ptr mechanism deserves its own mention: it is discouraged by RFC 7208 §5.5, some receivers penalize records that use it, and it is slow and unreliable to resolve. If you have ptr in your record, remove it.
One more that trips people up is the trailing catch-all. Every SPF record should end in exactly one all mechanism, usually -all (hardfail) or ~all (softfail). Multiple all mechanisms, or mechanisms placed after all (which can never be reached), signal a record that was edited by hand without understanding that evaluation stops at the first match. Validate the record after every change so a syntax slip surfaces immediately instead of in an aggregate report two weeks later.
How to fix a PermError
The fix depends on which cause you have, so diagnose first. Run your domain through an SPF validator that resolves every mechanism and reports the effective lookup count, the void lookups, and any syntax faults. Scott Kitterman's SPF record testing tools are the long-standing reference for this. Once you know the cause, the fix is one of the following:
- Over the 10-lookup limit: audit every
include:and remove senders you no longer use. This alone often recovers several lookups. Then consolidate stable senders with fixed IPs intoip4:/ip6:ranges, which count as zero lookups. If you genuinely need more than 10 services, reach for SPF flattening, but reduce senders before you flatten. - Too many void lookups: find the
include:,a, ormxmechanisms that resolve to nothing and delete them. These are almost always dead senders you already stopped using. - Two SPF records: merge them into one
v=spf1record. Combine the mechanisms, keep a single trailingall, and delete the extra TXT record. - Malformed syntax: fix the specific fault the validator flagged, remove any
ptrmechanism, and confirm the record ends in exactly oneall.
After any change, re-validate and then watch your DMARC aggregate reports over the next few days to confirm SPF is passing and aligning where you expect. A fix that validates clean but doesn't show up as an SPF pass in the reports means you fixed the syntax but missed a sender.
The DMARCit approach
SPF permerror is the kind of problem that is easy to fix once and easy to reintroduce a quarter later, because the lookup count drifts every time someone adds a sender. DMARCit's SPF surface is built around that reality: first-seen detection that flags new sending sources as they appear in your aggregate reports, and a monthly SPF audit that re-resolves your record and reports the effective lookup count, void lookups, and any syntax regressions before they turn into a permerror.
The honest framing is that this is early-warning, not real-time. DNS caching at receivers means nobody has a live SPF feed, and anyone claiming one is overstating what the data supports. What the monthly audit does buy you is catching the drift the month it happens, rather than the day a customer complains that your mail stopped arriving. For most small operators that cadence is the right trade between signal and noise.
If you are fixing a permerror as a prerequisite for DMARC enforcement, that is exactly the right order. Get SPF clean, confirm it in the reports, then walk the enforcement ramp. See /learn/p-quarantine-vs-p-reject for the policy decision and /enforcement-readiness for the guided ramp. Pricing is at /pricing.
FAQ
What is the difference between SPF PermError and TempError?
PermError is a permanent, structural failure: the receiver read your record and it is invalid or exceeds a hard limit, so retrying won't help. TempError is transient, usually a DNS timeout or SERVFAIL, and the receiver may treat the message differently and can succeed on a later attempt. PermError needs you to fix the record; TempError often clears on its own.
Does an SPF PermError mean my mail bounces?
Not necessarily. A permerror means SPF cannot pass, so it stops contributing to DMARC alignment. If DKIM still passes and aligns, the message can pass DMARC anyway. But you've lost an entire authentication path, some receivers treat SPF permerror harshly, and you are one DKIM problem away from failing DMARC entirely. Treat it as urgent even if mail is still flowing.
How do I get under the 10 DNS lookup limit?
Audit every include: in your record and remove senders you no longer use, which usually recovers several lookups. Consolidate stable senders with fixed IPs to ip4: / ip6: mechanisms, which count as zero lookups. If you genuinely send through more than 10 services, SPF flattening rewrites includes into IP literals. Reduce senders before you flatten.
Check your SPF record now
See your effective lookup count, any void lookups, and syntax faults before they turn into a permerror. We watch the record and flag drift the month it happens.