SPF Breaking From Too Many Includes? Flattening and Macro Fixes That Work
SPF PermError from 10+ DNS lookups? Flattening and subdomain delegation fix it.
By JustEmails Platform Team
I hit the 10-lookup limit on a Thursday afternoon. Zendesk, Mailchimp, SendGrid for transactional, Google Workspace, and a CRM I'd forgotten we'd connected. Twelve lookups. SPF PermError started bouncing every outbound message, and I didn't notice until a client asked why their invoice failed delivery.
Embarrassing? Yes. Preventable? Also yes.
The fix took four hours because I tried flattening first — the wrong approach for that setup. (I have a talent for picking the wrong tool on the first try.) This is the decision tree I wish someone had handed me before I started editing DNS records.
What We're Fixing
By the end of this, you'll understand why SPF breaks at 10 lookups, when flattening is the right fix (and when it isn't), and how to implement three different strategies: manual flattening, managed flattening services, and subdomain delegation. The right choice depends on how many senders you have, how often their IPs change, and whether you're okay with transactional mail coming from a subdomain.
Prerequisites
- Access to your domain's DNS (Cloudflare, Route 53, GoDaddy — wherever your NS records point)
- A list of every service that sends email on your domain's behalf
- Basic comfort with TXT records
- 30 minutes for the simple path, 2 hours if you're doing subdomain delegation across multiple senders
Why SPF Breaks at 10 Lookups
SPF has a hard limit: 10 DNS lookups per evaluation. Every include:, a:, mx:, ptr:, exists:, and redirect= counts as one lookup.
Here's the part that got me: nested includes inside vendor records count against your total too.
Here's what Google Workspace alone costs you:
include:_spf.google.com
→ include:_netblocks.google.com (lookup 2)
→ include:_netblocks2.google.com (lookup 3)
→ include:_netblocks3.google.com (lookup 4)
That's 4 lookups before you add SendGrid (1), Mailchimp (1), Zendesk (2-3 depending on configuration), or your CRM. Add a transactional sender and suddenly you're at 11 or 12. SPF returns PermError, which most receiving servers treat as a fail.
Check your current count:
dig +short TXT yourdomain.com | grep spf
Then run it through MXToolbox's SPF checker or dmarcian's SPF surveyor. Both show total lookups including nested ones.
Strategy 1: Manual Flattening
Flattening replaces include: statements with the actual IP addresses they resolve to. Instead of include:sendgrid.net (which triggers a lookup), you paste in SendGrid's IP ranges directly.
When this works: You have 1-2 vendors with stable IPs, you're comfortable re-flattening quarterly, and you don't mind the maintenance.
When this fails: Vendors rotate IPs frequently, you have 4+ senders, or nobody owns the DNS and maintenance won't happen.
Step 1: Resolve Each Include
For each include: in your SPF, resolve it to IPs:
dig +short TXT _spf.google.com
dig +short TXT sendgrid.net
dig +short TXT spf.protection.outlook.com
You'll get responses like:
"v=spf1 ip4:192.0.2.0/24 ip4:198.51.100.0/24 ~all"
Step 2: Consolidate Into One Record
Replace the includes with IP blocks:
Before (12 lookups):
v=spf1 include:_spf.google.com include:sendgrid.net include:mail.zendesk.com include:spf.mailchimp.com ~all
After (0 lookups, but long):
v=spf1 ip4:209.85.128.0/17 ip4:74.125.0.0/16 ip4:167.89.0.0/17 ip4:168.245.0.0/17 ip4:198.2.128.0/18 ip4:167.89.123.0/24 ~all
The TXT record length limit is 255 characters per string, but you can chain multiple strings in one record. DNS providers handle this differently — Cloudflare concatenates automatically, others need manual splitting.
Step 3: Set a Maintenance Calendar
Here's the catch nobody mentions in "just flatten it" advice: vendor IPs change. SendGrid rotates ranges. Google adds netblocks. A flattened record that worked in June breaks in September.
Set a monthly calendar reminder to re-check and re-flatten. Or accept that you'll find out via bounced mail — which, honestly, is how most people find out. Myself included. Twice.
Strategy 2: Managed Flattening Services
If manual flattening sounds tedious (it is), paid services automate it.
AutoSPF ($30/year for small domains) monitors your includes, resolves IPs nightly, and publishes a flattened record you point to with a single include. Your SPF becomes:
v=spf1 include:_spf.autospf.com ~all
And they handle the flattening on their side.
SPF Flattening from dmarcian (included in their $200+/year plans) does the same thing with better reporting.
Cloudflare Email Security (enterprise tier) includes dynamic SPF management.
The economics: if your time is worth more than $30/year in DNS maintenance, outsource it. Most teams should. I'm stubborn, so I didn't — and regretted it within six weeks.
Strategy 3: Subdomain Delegation (The Cleaner Fix)
Here's the approach I should have used on that Thursday.
Instead of cramming every sender onto the apex domain's SPF, move senders to subdomains. Each subdomain gets its own SPF record with its own 10-lookup budget.
Your apex domain:
v=spf1 include:_spf.google.com ~all
em.yourdomain.com (SendGrid transactional):
v=spf1 include:sendgrid.net ~all
mg.yourdomain.com (Mailgun marketing):
v=spf1 include:mailgun.org ~all
support.yourdomain.com (Zendesk):
v=spf1 include:mail.zendesk.com ~all
Each subdomain is an independent SPF evaluation. Ten+ senders, no lookup limit problems — because each lives on its own subdomain. Simple in theory. Annoying to set up. Worth it.
Setting Up Subdomain Delegation
Step 1: Plan your subdomain structure
Pick subdomains that make sense for your mail types:
| Sender | Subdomain | Mail type |
|---|---|---|
| SendGrid | em.yourdomain.com | Transactional |
| Mailchimp | mc.yourdomain.com | Marketing |
| Zendesk | support.yourdomain.com | Support tickets |
| CRM | crm.yourdomain.com | Sales sequences |
Step 2: Create the subdomain SPF records
For each subdomain, add a TXT record with that sender's SPF:
em.yourdomain.com. IN TXT "v=spf1 include:sendgrid.net ~all"
mc.yourdomain.com. IN TXT "v=spf1 include:spf.mailchimp.com ~all"
Step 3: Configure DKIM on each subdomain
DKIM needs to work for DMARC alignment. Add the vendor's DKIM CNAMEs for each subdomain. For SendGrid on em.yourdomain.com:
s1._domainkey.em.yourdomain.com. IN CNAME s1.domainkey.u12345.wl.sendgrid.net.
s2._domainkey.em.yourdomain.com. IN CNAME s2.domainkey.u12345.wl.sendgrid.net.
Step 4: Update sender configurations
In each vendor's dashboard, configure sending from the subdomain rather than the apex. SendGrid, Mailgun, Postmark — all support custom sending domains. Your transactional mail will now come from noreply@em.yourdomain.com instead of noreply@yourdomain.com.
Step 5: Handle DMARC alignment
Add a DMARC record for each subdomain, or let subdomain policy inherit from the apex via sp=:
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=reject; sp=quarantine; rua=mailto:dmarc@yourdomain.com"
The sp=quarantine means subdomains inherit a quarantine policy. Tune this based on your risk tolerance. I run sp=reject on production domains where every subdomain sender is authenticated. Aggressive? Maybe. But I've been burned by spoofed subdomains before, and once is enough.
Trade-offs
Subdomain delegation means transactional mail comes from em.yourdomain.com not yourdomain.com. Most recipients don't notice, but some enterprises have reply-to policies that flag subdomain senders. Test before committing.
The upside: zero maintenance. The vendor owns their subdomain's SPF, and their IP changes are their problem. You set it up once and forget it.
The Decision Tree
You have 1-2 vendors and time for quarterly maintenance? Manual flattening works. Cheap, direct, no dependencies.
You have 3+ vendors or hate DNS maintenance? Managed flattening service. AutoSPF at $30/year pays for itself in avoided debugging.
You have 4+ vendors and want a permanent fix? Subdomain delegation. More upfront work, zero ongoing maintenance.
You're already over 10 lookups and need a fix today? Flatten manually to stop the bleeding, then migrate to subdomain delegation over the next month. Don't do what I did and assume "temporary" means anything other than "permanent until it breaks again."
SPF PermError and Common Fixes
PermError: too many DNS lookups
You're over 10. Run dig +short TXT yourdomain.com | grep spf and count includes, then check each include's nested lookups. Flatten or delegate until you're under 10.
Mail from vendor X still failing SPF after flattening
Either you missed IP ranges, or the vendor rotated IPs since you flattened. Frustrating, I know. Re-resolve the vendor's SPF record and update your flattened IPs. Then set that calendar reminder you skipped the first time.
DMARC failing on subdomain mail after delegation
DKIM isn't configured for the subdomain. Add the vendor's DKIM CNAMEs specifically for the subdomain (s1._domainkey.em.yourdomain.com, not s1._domainkey.yourdomain.com).
SPF record exceeds 255 characters
Split into multiple quoted strings within the same TXT record. Most DNS providers handle this automatically. If yours doesn't, use this format:
yourdomain.com. IN TXT "v=spf1 ip4:192.0.2.0/24 ip4:198.51.100.0/24" "ip4:203.0.113.0/24 ~all"
Next Steps
If you're not sure whether your current SPF is even correct, our custom domain email setup guide covers the baseline DNS configuration that comes before this post. Already at p=reject on DMARC? The DMARC ramp guide covers the policy side.
For transactional email specifically — if you're choosing between SMTP relay and API for those SendGrid/Mailgun calls — SMTP vs API for transactional email breaks down the tradeoffs. And if you're running multiple brand domains (the use case where SPF bloat gets ugly fast), multi-domain email management covers the organizational patterns that keep DNS sane.
Beyond email, if you're managing click tracking or affiliate traffic, ClickzProtect handles the bot-detection side — different domain, same "too many moving parts" energy. JustAnalytics covers privacy-first analytics if you're consolidating tracking across properties. For sales teams running outbound sequences, VeloCalls handles the calling side with TCPA compliance built in. And if you're a dev team automating DNS changes via CI/CD, DevOS keeps your deployment workflows organized. (Yes, I'm plugging sibling products. No, I'm not sorry — they actually solve the problems they claim to.)
Frequently Asked Questions
How do I know if my SPF record has too many lookups?
Run your domain through an SPF checker like mxtoolbox.com/spf.aspx or use dmarcian's SPF surveyor. Both count total lookups including nested includes. If you see "Too many DNS lookups" or "PermError," you're over 10. Each include:, a:, mx:, ptr:, exists:, and redirect= counts as one lookup. Nested includes inside vendor records count against your total too — _spf.google.com alone burns three lookups before you add anything else.
Does flattening break when vendor IPs change?
Yes. That's the maintenance risk nobody warns you about upfront.
When SendGrid or Mailgun rotates their IP ranges (happens roughly quarterly for some providers), your flattened record becomes stale. Mail from their new IPs fails SPF. You either re-flatten manually on a schedule, use a paid flattening service that monitors and updates automatically, or switch to subdomain delegation so the vendor manages their own SPF. Most teams doing flattening set calendar reminders for monthly re-checks at minimum.
Can I use SPF macros instead of flattening?
Macros reduce lookups by deferring evaluation to the receiving server, but they're complicated and not universally supported. The % macro (sender IP) lets you build dynamic records, but older mail servers handle them inconsistently. For most teams, subdomain delegation is simpler and more reliable than macros. Macros are a power-user tool for edge cases — not a first choice for fixing lookup limits.
What's the difference between flattening and subdomain delegation?
Flattening replaces include: statements with the actual IP addresses they resolve to, collapsing lookups into one long TXT record. Subdomain delegation moves senders to their own subdomains (em.yourdomain.com for SendGrid, mg.yourdomain.com for Mailgun) where each has its own SPF record with its own 10-lookup budget. Flattening requires ongoing maintenance; subdomain delegation is set-and-forget but means your transactional mail comes from a subdomain rather than the apex.
Try JustEmails
Unlimited custom domain email hosting for $49/year flat — unlimited domains, unlimited email accounts, 10 GB storage (expandable), full IMAP/SMTP/POP3. Built for agencies, freelancers, and anyone managing email across more than one domain.