Where the limit comes from
RFC 7208 states that a receiver may trigger at most ten DNS queries caused by mechanisms or modifiers while evaluating an SPF record. The limit protects receivers from records that are nested arbitrarily deep and would cause dozens of queries for every incoming message. If it is exceeded, the result is permerror, and the domain is effectively treated as having no SPF.
The limit applies per evaluation, that is to the whole tree consisting of the domain's record and every record it includes. An include that itself contains three more includes therefore costs you four lookups, not one.
Which mechanisms count
Only mechanisms that require the receiver to query DNS count towards the limit. The address mechanisms ip4 and ip6 as well as all cost nothing, because the information is right there in the record. There is also a second limit: at most two lookups may return an empty result (void lookups), for example an include pointing to a hostname without an SPF record. Beyond that, the receiver may abort with permerror as well.
- include: one lookup plus every lookup of the included record
- a: one lookup (A or AAAA query)
- mx: one lookup for the MX list; the address queries for the individual mail servers are capped at ten per mx and do not count towards the overall limit
- ptr: one lookup, obsolete and ignored by many receivers
- exists: one lookup
- redirect=: one lookup plus every lookup of the target record
- ip4, ip6, all: no lookup
What typical services cost
The cost of an include depends on how the provider has built its own record. It can change whenever the provider restructures, which is why a regular check with the SPF checker pays off. The following values are typical at the time of writing.
- Microsoft 365: include:spf.protection.outlook.com usually costs two lookups
- Google Workspace: include:_spf.google.com costs three lookups, because the record includes three netblock records
- Mailchimp: include:servers.mcsv.net, usually one to two lookups
- SendGrid: include:sendgrid.net, one to two lookups
- HubSpot, Zendesk, Salesforce: between one and four lookups each, depending on region and product
Add that up and a record with Microsoft 365, Google Workspace, a newsletter tool, a CRM and a ticket system already sits at ten or more lookups before the old hosting provider even joins the list.
Strategy 1: Clean up and use ip4/ip6
The most effective step is the most boring one: check which services still actually send mail on behalf of the domain. The hosting provider from three years ago, the newsletter tool the client cancelled, and a developer's test account are the classics. DMARC aggregate reports reliably show which sources were active in recent weeks.
Services with fixed IP addresses, such as your own mail server or a relay in the data centre, go in directly via ip4 or ip6. That costs no lookup. Important: only for addresses you control yourself. Copying the IP addresses of large providers is flattening through the back door.
Before, 12 lookups:
v=spf1 include:spf.protection.outlook.com include:_spf.google.com include:servers.mcsv.net include:sendgrid.net include:mail.zendesk.com include:spf.old-host.example mx -all
After, 5 lookups:
v=spf1 include:spf.protection.outlook.com include:sendgrid.net include:mail.zendesk.com ip4:203.0.113.10 -allStrategy 2: One subdomain per sender
Every domain and every subdomain has its own lookup limit. Bulk senders such as newsletter tools, CRM systems or transactional mail services do not have to send from the main domain. Set up newsletter.example.com or crm.example.com with its own SPF record and let the service use that subdomain as the envelope from address.
This not only relieves the main domain's record, it also separates reputation: a newsletter with a high complaint rate does not drag the transactional mail down with it. For DMARC you only need to make sure the subdomain is covered by sp= or by its own DMARC record.
example.com:
v=spf1 include:spf.protection.outlook.com ip4:203.0.113.10 -all
newsletter.example.com:
v=spf1 include:servers.mcsv.net -all
crm.example.com:
v=spf1 include:_spf.salesforce.com -allStrategy 3: Flattening and SPF macros
Flattening replaces every include with the resolved IP networks. The record then has zero lookups but quickly grows to several hundred characters. The real problem: as soon as a provider changes its addresses, your record is wrong, and you only notice when mail lands in spam. Without an automated process that regenerates the record daily, flattening is a maintenance risk.
SPF macros are a tool for special cases. With exists:%{i}._spf.example.com exactly one query is made per sending IP, and you control the answer in your own zone. That reduces the record to a single lookup but moves the complexity into DNS automation that you have to run or buy. For most agency clients, cleaning up plus subdomains is the better choice.
Step by step
In this order you solve the problem within an hour in most cases.
- Run the record through the SPF checker and note the lookup count per include.
- Clarify with the client which services have sent mail in the last twelve months. Use DMARC reports as evidence.
- Remove includes that are no longer used, drop ptr and unnecessary mx or a mechanisms.
- Add your own servers via ip4 or ip6.
- Move bulk senders to subdomains with their own SPF record.
- Publish the new record, keep the TTL short and check the DMARC reports after a few days.
Frequently asked questions
- Does an include count if it is never reached?
- Yes. Receivers evaluate the record left to right and stop at the first match, but the limit refers to the queries needed up to that point. For a spoofed message that matches no mechanism, every mechanism is evaluated. That is why you have to budget for the whole tree.
- Why does my tool show nine lookups and another one eleven?
- Provider records change, and some tools count mx or void lookups differently. The count according to RFC 7208 is what matters. If you are close to the limit, plan for headroom in any case, because a provider can add an include at any time.
- Can I raise the limit above ten?
- No. The limit is enforced by the receiver, not by you. There is no modifier that would let you increase it.