What the limit is
RFC 7208 section 4.6.4: mechanisms that require DNS lookups (include, a, mx, ptr, exists) and the redirect modifier are limited to ten in total, counted across the whole evaluation including every record pulled in by include. Exceeding it produces a permerror, and a permerror means the receiver treats the domain as having no usable SPF at all. Not "fails SPF"; "has no SPF". Combined with a DMARC policy that relies on SPF alignment, that pushes legitimate mail into spam.
The limit exists to stop SPF being used as a DNS amplification attack, and receivers really do enforce it. Google, Microsoft and every serious mail provider stop at ten.
What counts
| Term | Lookups | Notes |
|---|---|---|
| include:_spf.example.com | 1, plus everything inside it | The record you include is fetched and evaluated in full. Its own includes count against your ten. |
| a | 1 | Looks up the A/AAAA record of the domain (or the named host with a:host). |
| mx | 1, plus one per MX host | The MX lookup itself, then an address lookup for each mail server it returns. RFC 7208 separately caps the number of MX hosts at ten. |
| ptr | 1 or more | Deprecated. Slow, unreliable and counts. Remove it. |
| exists: | 1 | Rare outside macro-based setups. |
| redirect= | 1 | Replaces the current record with another; the target's lookups count too. |
| ip4: ip6: all | 0 | Free. These are the mechanisms you want. |
A typical business record looks harmless: v=spf1 include:_spf.google.com include:sendgrid.net include:mailgun.org include:servers.mcsv.net ~all. That is four includes. But Google's record includes three more records of its own, SendGrid's includes another, Mailchimp's is nested, and suddenly you are at eleven. The record is now worthless and nobody has changed anything visible.
How to see your count
The email deliverability checker parses the SPF record into a tree, follows every include and redirect, and shows the running lookup count with each branch labelled. A count over ten is flagged as a fail. The tree view also tells you which include is the expensive one, which is what you need for the next step.
By hand: dig +short TXT example.com, then dig +short TXT _spf.google.com for each include, recursively, keeping a tally. It is tedious, which is why people do not do it and why the problem is so common.
Getting back under ten
1. Remove what you no longer use
Records accumulate. The marketing platform from three years ago, the helpdesk you migrated off, the a and mx mechanisms someone added "to be safe" when the mail server was in the office. Each one is a lookup. Audit every term against the services that actually send mail today. mx is almost always removable: your inbound mail servers rarely send outbound mail directly.
2. Replace includes with ip4/ip6 where the addresses are stable
If a provider publishes a fixed set of sending addresses (many do, for exactly this reason), list them as ip4: ranges instead of including their record. Zero lookups. The trade-off is that you must update your record if they change their ranges, so only do this for providers that commit to stable ranges and announce changes.
3. Use subdomains for bulk senders
Marketing and transactional platforms usually let you send from a subdomain (news.example.com, mail.example.com). Each subdomain gets its own SPF record with its own budget of ten. Your apex record then only needs the handful of services that genuinely send as @example.com. This also isolates reputation: a spam complaint on the newsletter domain does not hurt your invoices.
4. SPF flattening
Flattening resolves every include down to its IP addresses and publishes those directly. It works, and several services will do it for you automatically and keep it updated. The risk is staleness: if you flatten by hand and a provider adds a sending range, mail from that range fails SPF until you notice. If you use a flattening service, you have added a dependency that can publish a broken record on your behalf. I would use it as a last resort after the first three steps, not as a first move.
5. Stop relying on SPF alone
DMARC passes if either SPF or DKIM aligns. Every reputable provider supports DKIM signing with your domain. If all your senders DKIM-sign, an SPF permerror is a warning rather than an outage. Set DKIM up for every service before you spend a weekend on SPF arithmetic. See DMARC policies for how the two interact.
Other SPF mistakes that look like this one
- Two SPF records. Two TXT records starting
v=spf1is also a permerror. Merge them into one. - A record over 255 characters in a single string. TXT records must be split into multiple quoted strings; most DNS providers do this for you, some do not.
- Void lookups. An include that points at a name with no TXT record counts as a "void lookup", and more than two of those is also a permerror. Usually a provider you stopped paying for.
+allat the end. Means anyone may send as you. Receivers treat it as no SPF.-allbefore you were ready. Hard fail is correct eventually, but only once every legitimate sender is listed. Start with~alland let DMARC reports tell you what you missed.