"Too many DNS lookups" means the receiving server needed more than 10 DNS queries to check your SPF record. It hits the ceiling, stops and returns an error. Your mail then fails SPF, even when the record contains no typo you could spot. On cold email domains it tends to appear right after someone connects one more tool.
The repair order I use:
- Write down every service that sends mail from the domain.
- Remove the ones that have no reason to be there.
- Move extra sending roles to their own domain or subdomain.
- Swap includes for IP addresses where you own the IPs.
- Flatten what remains only when the tool stack has stopped changing.
What does "too many DNS lookups" actually mean?
SPF is a TXT record in DNS that names the servers allowed to send mail for your domain. That is how Google's Workspace setup guide explains it.
Receivers do not read that record as a fixed list. The SPF standard, RFC 7208, describes the check step by step: the receiver tests your record against the server that is delivering the message.
A DNS query is the receiver asking DNS for more information. Six terms force one during that evaluation: include, a, mx, ptr, exists and redirect. The standard allows 10 of them per check, and the eleventh turns the result into a permanent error, called permerror. Plain ip4 and ip6 entries need no query, so they cost nothing.
Microsoft Learn puts it in practical terms. SPF validation fails once the check needs too many lookups. Each include costs at least one, and an include whose target record carries its own includes costs more.
That nesting is why the record looks harmless. Google's guide permits up to 10 include tags in one record, yet a single include you can read may hide several lookups you cannot see. The vendor's record behind it calls other records.
So this is plumbing, and plumbing comes BEFORE copy. Better subject lines do nothing for a sender that fails authentication. Fix the record first. Then scale.
Why do cold email domains hit the limit so fast?
Every tool you connect asks for "just one line" in DNS, and nobody counts what that line pulls in behind it. The table shows how a record typically grows when no one owns it. The counts are illustrative; your real numbers come from expanding each vendor's record.
| Month | What got added | Term added | Lookups added |
|---|---|---|---|
| 1 | Company mailbox provider | include | 1, plus the 2 nested inside it |
| 2 | Sequencing tool that sends from its own servers | include | 1, plus 1 nested |
| 3 | Warm-up service | include | 1 |
| 4 | CRM that sends follow-ups | include | 1, plus 2 nested |
| 5 | "mx" and "a" copied from a template | mx, a | 2 |
| 6 | Helpdesk on the same domain | include | 1, plus 1 nested |
The nesting is easy to miss: Microsoft's SPF documentation says an include that points to a record with three more includes costs 4 lookups in total, not 1. Six small changes, 13 lookups, three over the cap.
Scale multiplies the risk. A cold program usually runs on a pool of 10 to 20 domains, with 20 to 40 mailboxes spread across them. If each of those domains carries the same pasted record with the whole company tool stack inside, one new include can break authentication on all of them in a single afternoon.
That is why cold domains never inherit the company stack. Keep cold email off the domain your invoices come from. We give each client dedicated sending IPs, separate even across their own domains, so a reputation problem on one IP stays contained instead of spreading to every domain. A cold domain's record then only has to name the one or two things that really send from it.
The mistakes I see most often:
- one domain carrying company mail, newsletters and cold outreach together
- includes for tools cancelled months ago
- "mx" and "a" copied from a template onto a domain whose servers never send anything
- tools that send through your own mailboxes added to SPF anyway
- one long record pasted onto 20 fresh domains
Sending more fixes none of this. Push 100,000 emails this week or next month - with broken foundations, the result stays the same. Volume comes last, never first.
How do you spot an SPF failure before mail starts bouncing?
SPF trouble shows up as a sudden drop. Opens and replies fall across every inbox on a domain in the same week, usually right after a tool, domain, subdomain or mailbox was added. Your sending tool raises authentication warnings while the copy and the list have not changed.
Test messages show an SPF result other than pass in the headers. Go over 10 lookups and Microsoft documents that the message fails SPF with a permanent error, shown as permerror. Google's sender guidelines say messages that fail authentication might be marked as spam or rejected with a 5.7.26 error.
Syntax checkers can mislead you here. The lookup count happens at evaluation time and includes everything nested inside each include, so a checker that only validates format will happily report that the record looks fine. Microsoft's guide makes the same point: fewer than 10 include statements does not guarantee fewer than 10 DNS lookups.
Sort the problem into one of three types before you touch DNS.
Record problem: the header result is anything other than pass, for SPF and DKIM on cold email domains alike. Fix DNS before anything else.
Content or volume problem: SPF passes and mail still lands in spam. Look at the copy, the daily volume per mailbox and the warm-up.
Data problem: mail bounces because the addresses are bad. My team and I check every address before it gets a single email and hold the bounce rate under 0.5%. That is a list issue, covered in our lists and targeting FAQ.
Triage in this order:
- Write down every change from the last 14 days: tools, domains, subdomains, mailboxes.
- From each sending domain, send a test to a few personal inboxes and read the SPF line in the headers.
- Expand the record and count each lookup term, including those nested inside vendor includes. Run
dig TXT yourdomain.com +short, then run it again for every domain named in an include, and add up the lookup terms you find. - List every service that sends from the domain, including quiet ones such as the CRM, the helpdesk and the invoicing tool.
- Review the copy only after all of that.
What is the safest fix when you have too many senders?
Make the cheapest change first and stop the moment the check passes.
- Cut senders that do not belong. Cancelled tools, duplicate includes, "mx" and "a" terms on domains whose servers never send. For each tool, find out whether it sends through your mailboxes or from its own servers. SPF only needs the second group.
- Split roles across domains. Company mail stays on the main domain, and cold outreach moves to separate domains with short records. Microsoft names subdomains and consolidating email services as ways to cut lookups, and reminds you that each subdomain you send from needs its own SPF record.
- Use IP addresses where the IPs are yours. Microsoft recommends swapping include values for IP addresses. With dedicated sending IPs this stays clean, because ip4 and ip6 sit outside the standard's list of lookup terms.
- Flatten vendor includes last. Flattening replaces a vendor's include with the IP addresses behind it. A manually flattened record is a snapshot of the IPs authorized when it was made, and it goes stale the day the vendor changes servers. Microsoft advises against flattening its own include because its sending IPs change frequently. So someone has to own the record and re-check it on a schedule.
Should you flatten SPF or split the sending domain?
| Situation | Risk | Move |
|---|---|---|
| The stack is still growing, with a new tool every quarter | Every addition reopens the problem | Split: the new role gets its own domain or subdomain |
| The stack is stable, and one or two vendor includes push the count over | Flattened IPs go stale when the vendor changes servers | Flatten carefully, with an owner and a monthly re-check |
| Company mail and cold tools share one domain | A cold email problem lands on invoices and support mail | Move cold sending to separate domains now |
| Dozens of cold domains carry copy-pasted records | One edit breaks every domain at once | Trim each record to what actually sends from it |
| You control the sending IPs | Little beyond typos | List the IPs directly instead of an include |
My rule: split a stack that is still growing, flatten one that has stopped, and touch sending volume only after every domain passes.
How should a founder structure cold email domains from day one?
My order on every domain is the same:
- SPF, DKIM and DMARC go in and pass before anything is sent, at any volume.
- New mailboxes warm up for at least 10-14 days before they are used.
- Volume goes up only after warm-up, never before.
Spreading sending across many domains also limits the damage: when one record breaks, a few inboxes stop and the rest keep sending.
Scope the list to the program, because a single-market campaign with a two-person sales team needs far fewer pieces than a program running into several countries. Each domain's record should list only the senders actually used, and nothing from the marketing team's setup should be copied in by default.
If you are still choosing what to send with, the cold email tool stack and the choice between Workspace and Microsoft for cold email decide which includes you carry. Decide what each domain will send through before you write a single record.
What does a fixed SPF record look like?
Before, with one domain doing everything:
v=spf1 include:_spf.mailhost.example include:send.sequencer.example include:warmup.example include:mail.crm.example include:helpdesk.example mx a ~all
After, with roles split across domains:
Company domain:
v=spf1 include:_spf.mailhost.example include:helpdesk.example ~all
Each cold domain:
v=spf1 include:_spf.mailhost.example ip4:203.0.113.10 ~all
The company domain keeps the tools the business runs on. Each cold domain names its mailbox provider and its own dedicated IP, and that is the whole record. The closing "~all" is a softfail: mail from senders missing from the list is treated as suspect, but the standard says receivers should not reject it on that basis alone.
Send tests from each domain to a few inboxes and confirm a pass before you add volume. Google notes that SPF changes can take up to 48 hours to take effect. While authentication is unstable, hold the volume where it is. Scaling cold email comes after this step.
If your SPF record keeps breaking as tools get added and you want a second pair of eyes on the stack, send the record first. Book a call.
Questions founders ask about SPF lookups
Can a domain have two SPF records?
No. RFC 7208 says that when a lookup returns more than one SPF record for a domain, the SPF check returns permerror, the same failure as too many lookups. This often happens when a new tool's setup guide tells you to "add" an SPF record. Merge the new include into your existing v=spf1 line instead of creating a second TXT record.
Can a dead include break SPF even under 10 lookups?
Yes. Under RFC 7208, an include pointing to a domain that publishes no SPF record makes the whole check return permerror, whatever your count. The standard also recommends capping "void lookups", queries that come back with no answer, at two. Leftover includes and "a" or "mx" terms from cancelled tools are the usual source of both.
Can a flattened SPF record get too long?
Yes, and flattening is a common way to get there, because it swaps short includes for long lists of IP addresses. A single DNS text string holds at most 255 characters, so RFC 7208 lets a long record be split into several quoted strings that receivers join without spaces. The standard also advises keeping the full DNS answer under 450 bytes so it fits in a single DNS reply packet.
Should I keep a ptr term in my SPF record?
Remove it. RFC 7208 says the ptr mechanism should not be published: it is slow, unreliable when DNS has errors and puts load on shared reverse-DNS servers. It also costs a lookup toward the 10. Old hosting panels and templates still add it, so check for it on every cold domain you inherit.
Does "~all" or "-all" matter on a cold email domain?
They tell receivers different things. Under RFC 7208, "-all" produces a fail, which a receiver may reject outright, while "~all" produces a softfail, which the standard says should not lead to rejection on its own. Neither helps once the check ends in permerror, because evaluation stops before it reaches the "all" term.
