Siftsmith
← Email Security Signals

SPF PermError: too many DNS lookups

An SPF record may trigger at most 10 DNS-querying terms, counted across every record it includes. Go over and receivers return permerror, so SPF can fail even for mail from servers you authorised. This page covers what counts, how to count it, how to get back under the limit, and how to check the lookup count for a whole list of domains in one run.

What the 10-lookup limit is

RFC 7208, the SPF standard, says in section 4.6.4: “SPF implementations MUST limit the total number of those terms to 10 during SPF evaluation” and “If this limit is exceeded, the implementation MUST return ‘permerror’.”

Counts toward the 10include, a, mx, ptr, exists (mechanisms) and redirect (modifier)
Doesn’t countip4, ip6, all, and the exp modifier
Void lookupsImplementations SHOULD limit “void lookups” (terms whose lookup returns no records or a non-existent domain) to two; exceeding that limit is also a permerror
Per mx / ptrEach MX or PTR record may lead to at most 10 A/AAAA lookups, on top of the overall limit (over that, mx is a permerror; for ptr the extra records are ignored)

Two more rules matter when counting. An include runs a full SPF check against the included domain (section 5.2), so every term in the included record counts too, and so on down the tree. And a redirect= is ignored when the record also has an all mechanism (section 6.1), so it doesn’t count in that case.

What happens when you go over

Microsoft’s SPF documentation says that if the lookup count “is greater than 10, the message fails SPF with a permanent error (also known as a permerror)”, and that the receiving system may bounce it with an NDR such as “The message required too many lookups.” Google’s troubleshooting page says exceeding the limit causes “your SPF record validation to fail”, and warns that error messages “might include warnings that you don’t have an SPF record (even if you do have one).”

The failure can be intermittent. Receivers evaluate the record left to right and stop at the first match, so, as Microsoft notes, mail from a sender listed early may pass while mail from a sender further along fails. A record that “mostly works” can still be over the limit.

For bulk senders this is more than a warning: Gmail, Yahoo and Outlook.com all require SPF, and Microsoft says it must pass. See what the bulk sender rules require.

Sources: RFC 7208 sections 4.6.4, 5.2 and 6.1; Microsoft Learn, Set up SPF to identify valid email sources for your Microsoft 365 domain; Google Workspace Help, Troubleshoot SPF issues (all checked September 2026).

How to count lookups

  1. Start at the domain’s own SPF record. Count one for each include, a, mx, ptr, exists and redirect. Skip ip4, ip6 and all.
  2. For each include: and redirect= target, fetch that domain’s SPF record and count its terms the same way.
  3. Keep going until no includes are left. The total across the whole tree is the number that must stay at 10 or below.

The number of include: terms you can see is not the lookup count. Microsoft’s example: an include that points to a record with three more includes costs four lookups. Real records from our run on 27 September 2026:

DomainIncludes in its own recordTotal lookups
posthog.com610
github.com810
atlassian.com66
hubspot.com0 (one redirect=)4

posthog.com and github.com both sit exactly at the limit, so adding one more sending service would push either over.

How to fix it

A caution on SPF flattening

Flattening replaces includes with the IP addresses they currently resolve to. It fixes the count today, but the IPs are a snapshot: when a provider adds a range, your flattened record doesn’t follow and mail from the new range fails SPF. Microsoft says not to flatten its own include (spf.protection.outlook.com) or any service with changing IPs, and if you do flatten, to document what you replaced and review it at least quarterly. Try the options above first.

After any change, allow time for it to spread: Google says 24–48 hours.

Check the SPF lookup count for a list of domains

Email Security Signals reads each domain’s SPF record from public DNS, follows its includes and redirects, and returns the total lookup count with the rest of its email-authentication checks. It suits auditing client domains, a prospect list or a vendor list, where checking one domain at a time in a web tool doesn’t scale.

Input: paste domains, URLs or email addresses into Domains on the Apify Store page, or send JSON through the API:

{
  "domains": ["posthog.com", "https://www.github.com", "jane@atlassian.com"],
  "maxConcurrency": 5
}

SPF fields in each result row:

spf.lookupCountTotal DNS-querying terms across the whole include/redirect tree
spf.lookupCountIsMinimumtrue when the tree couldn’t be walked fully (an include or redirect lookup failed, or the tree was more than 10 levels deep or needed more than 40 record fetches), so the count is a lower bound
spf.validtrue when there is exactly one SPF record and it needs 10 or fewer lookups
spf.record, spf.recordCountThe record itself, and how many SPF records the domain publishes (more than one is also a permerror)
spf.allQualifierThe effective all: -all, ~all, ?all or +all, following redirect=; null when there is none or it can’t be determined
sendingVendors, spfIncludesServices named in the domain’s own includes (SendGrid, Mailchimp, Amazon SES, …), and any includes not in the vendor table, listed raw: a starting point for deciding what to remove
issuesspf_too_many_lookups (over 10, high severity), spf_near_lookup_limit (9 or 10, low), spf_multiple_records, spf_include_error (an include or redirect target with no SPF record or more than one), spf_lookup_count_truncated
bulkSenderCompliantfalse whenever SPF is over 10 lookups

For a domain over the limit, the issue reads, for example, “SPF needs 14 DNS lookups (limit is 10); receivers return permerror.” Export to CSV and sort by the spf/lookupCount column, or filter issues for spf_too_many_lookups.

What the count doesn’t cover: void lookups (the limit of two), the 10-address limit inside each mx or ptr, and %{…} macros, which are counted but not expanded. DNS is read through Cloudflare’s public resolver at run time.

FAQ

How much does it cost to check SPF lookups for a list of domains?

$0.02 per graded domain ($20 per 1,000), with no subscription. Domains that don’t exist, IP addresses, unparseable inputs, DNS lookup failures and duplicates come back as free rows. Set a max charge per run and the run never costs more than that.

Does ~all versus -all change the lookup count?

No. all never causes a DNS query. The qualifier only decides what happens to mail from servers the record doesn’t list.

My record has only five includes. How can it be over 10?

Nested includes. A provider’s include often includes further records of its own, and every one of those terms counts. posthog.com’s six includes add up to ten lookups.

Can I check domains I don’t own?

Yes. SPF records are public DNS records that every receiving mail server reads. No email is sent and no login is used.

Check your list on the Apify Store →