What the error means
SPF limits how much DNS work one check may cause. RFC 7208 (section 4.6.4) allows at most 10 mechanisms and modifiers that need a DNS lookup while evaluating a record, including everything pulled in through include. A record that goes over the limit returns permerror, a permanent error. For DMARC that is the same as no SPF pass at all, for every message, not only for the senders past the tenth lookup.
Authentication-Results: mx.example.net;
spf=permerror (too many DNS lookups) smtp.mailfrom=example.com
The wording varies by receiver; some just say spf=permerror. The Email Header Analyzer shows the result from a received message.
What counts
| Term | Counts toward 10 | Notes |
|---|---|---|
include: |
Yes, 1, plus everything inside it | Nested includes add up |
a, a: |
Yes, 1 | |
mx, mx: |
Yes, 1 | Plus up to 10 address lookups for the MX hosts |
exists: |
Yes, 1 | |
ptr |
Yes, 1 | Deprecated, remove it |
redirect= |
Yes, 1 | |
ip4:, ip6:, all |
No | Free |
There is also a limit of 2 void lookups (names that return no records or NXDOMAIN); a third gives permerror as well.
Why records go over
Each provider's include is itself a tree. A single include: for a large mail provider can cost three or four lookups once its own includes are resolved. Add a marketing tool, a CRM, a helpdesk and a billing system, and you pass 10 quickly. Old includes for services you stopped using are the most common waste.
v=spf1 include:_spf.google.com include:spf.protection.outlook.com include:servers.mcsv.net
include:sendgrid.net include:mail.zendesk.com include:spf.esp.example.net a mx ~all
(Shown on two lines for reading; in DNS it is one TXT value.)
How to fix it
- Remove what you don't use. Check each include against a service that still sends mail. Drop
ptr, and dropaandmxunless your web or mail server really sends mail directly. - Move senders to subdomains. If a newsletter tool uses its own return-path such as
bounce.example.com, its SPF lives there, not in your apex record. Many services offer this as "custom return-path" or "domain authentication". - Replace stable includes with IPs. If a provider publishes a short, rarely changing list of addresses,
ip4:andip6:cost nothing. Be careful: if the provider changes its IPs, your record silently goes stale. - Flattening services rewrite includes into IP lists automatically and keep them updated. They work, but they add a dependency on a third party for your mail.
- Lean on DKIM. DMARC needs one aligned pass. A service that signs with your domain doesn't need to be in SPF for DMARC to pass, although SPF on its own still helps with some filters.
A trimmed version of the record above:
v=spf1 include:_spf.google.com include:spf.esp.example.net ~all
with the other services moved to their own return-path subdomains.
Checking the count
Count recursively: open every include, then every include inside it. Our checker does this for you and shows the total. From a terminal you can follow the chain with dig:
dig +short TXT example.com
dig +short TXT _spf.google.com
Related
- SPF multiple records: the other common permerror.
- SPF softfail vs fail: choosing the
allqualifier. - spf=none: when no record is found.
- SPF record: the record syntax.
Run your domain through the SPF Checker to see every include and the total lookup count.