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.
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 10 | include, a, mx, ptr, exists (mechanisms) and redirect (modifier) |
|---|---|
| Doesn’t count | ip4, ip6, all, and the exp modifier |
| Void lookups | Implementations 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 / ptr | Each 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.
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).
include, a, mx, ptr, exists and redirect. Skip ip4, ip6 and all.include: and redirect= target, fetch that domain’s SPF record and count its terms the same way.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:
| Domain | Includes in its own record | Total lookups |
| posthog.com | 6 | 10 |
|---|---|---|
| github.com | 8 | 10 |
| atlassian.com | 6 | 6 |
| hubspot.com | 0 (one redirect=) | 4 |
posthog.com and github.com both sit exactly at the limit, so adding one more sending service would push either over.
a and an mx that name the same server, each cost a lookup.a, mx or a vendor include with ip4/ip6 where the addresses are stable. Microsoft recommends this only for vendors with “a stable, documented set of sending IP addresses”, and says you then have to watch for IP changes yourself. Google notes each string in an SPF record is limited to 255 characters.marketing.example.com, support mail on support.example.com, and so on. Each subdomain has its own SPF record and, in Microsoft’s words, “its own 10 lookup budget”. This also keeps a bulk sender’s reputation off your main domain.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.
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.lookupCount | Total DNS-querying terms across the whole include/redirect tree |
|---|---|
spf.lookupCountIsMinimum | true 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.valid | true when there is exactly one SPF record and it needs 10 or fewer lookups |
spf.record, spf.recordCount | The record itself, and how many SPF records the domain publishes (more than one is also a permerror) |
spf.allQualifier | The effective all: -all, ~all, ?all or +all, following redirect=; null when there is none or it can’t be determined |
sendingVendors, spfIncludes | Services 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 |
issues | spf_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 |
bulkSenderCompliant | false 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.
$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.
~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.
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.
Yes. SPF records are public DNS records that every receiving mail server reads. No email is sent and no login is used.