SPF Flattening: How to Fix Too Many DNS Lookups
SPF flattening fixes the 10 DNS lookup limit by replacing include: mechanisms in your SPF record with the actual IP addresses they resolve to. IP ranges don't consume lookups, so a flattened record sidesteps the limit entirely. If your SPF record is returning PermError and silently failing DMARC alignment on some receivers, exceeding that limit is almost certainly the cause.
Use the SPF checker to see your current lookup count. If it's at or above 10, you have a problem to fix.
The 10 DNS lookup limit
SPF has a hard limit: evaluating your record can require at most 10 DNS lookups. Each include:, a:, mx:, and redirect= mechanism that needs a DNS query counts toward this limit.
The problem is that ESPs chain their own includes. A single include:_spf.google.com might resolve to two or three nested includes, each consuming a lookup. Add Mailgun, SendGrid, Resend, and Google Workspace to the same SPF record and you can exceed 10 lookups easily.
When this happens, SPF returns PermError, a permanent error, not a soft fail. Some receivers treat PermError the same as SPF fail, which means SPF won't contribute to DMARC alignment for those messages, which means your alignment percentage drops.
The tricky part: it's receiver-dependent. Some receivers are lenient about the lookup limit. Others are strict. So you might have consistent DMARC alignment with Google but failures with Microsoft or Proofpoint, seemingly at random.
Use the SPF checker to see your current lookup count. If it's at or above 10, you have a problem to fix.
What SPF flattening is
SPF flattening replaces the include: mechanisms in your record with the actual IP addresses those includes resolve to. Instead of:
v=spf1 include:_spf.google.com include:_spf.resend.com include:sendgrid.net ~all
A flattened record would look like:
v=spf1 ip4:74.125.0.0/16 ip4:209.85.128.0/17 ip4:149.72.0.0/16 ip4:208.117.48.0/20 ~all
IP ranges don't require DNS lookups; they're just compared against the sending IP directly. A fully flattened record uses zero of your 10 lookup budget.
Manual flattening vs. dynamic SPF flattening services
Manual flattening: You look up each include, find the IPs it resolves to, and write them directly into your SPF record. The SPF checker shows you the resolved IPs for your current record, which is a starting point for this.
The problem with manual flattening: ESP IP ranges change. When Resend adds a new sending range or SendGrid rotates infrastructure, your flattened record immediately becomes incorrect. The include mechanisms would have caught the new IPs automatically; your flattened record won't. Mail from new IPs will fail SPF.
Dynamic SPF flattening services: Services like Dmarcly, Valimail, and others maintain the flattened IP lists for you and update them automatically when ESP ranges change. You point your SPF record at their DNS mechanism, which resolves to a pre-flattened list they keep current.
The trade-off: you're now dependent on their DNS infrastructure for your SPF. If their resolver has issues, your SPF evaluations are affected. It's a reliability dependency in exchange for not having to manually maintain IP lists.
What to do
For most indie developers with 2-3 ESPs:
-
Count your lookups with the SPF checker. If you're at 8 or more, you're at risk; 10 or above is a confirmed problem.
-
Audit your includes. Remove any ESPs you're no longer using. Every removed include saves lookups. This alone often brings you under the limit.
-
Combine includes where possible. If you're using Google Workspace, check whether their include already covers Gmail sending. If you have redundant or overlapping includes, eliminate them.
-
If you're still over the limit after cleanup: evaluate dynamic flattening. For a small operation, a service that maintains the IP lists for you is usually worth the dependency.
The thing you don't want to do is flatten manually and then forget about it. A flattened record that goes stale is worse than the original problem; it will fail silently as ESP infrastructure changes, and you won't know until alignment starts dropping in your DMARC reports.
FAQ
SPF flattening is the practice of replacing include: mechanisms in your SPF record with the actual IP addresses those includes resolve to. The goal is to reduce DNS lookups below SPF's hard limit of 10, which prevents PermError failures that cause DMARC alignment issues.
Exactly 10. The limit applies to mechanisms that require DNS resolution: include:, a:, mx:, ptr:, and redirect=. Each nested include counts separately, so include:_spf.google.com might consume 2-3 lookups depending on how Google's SPF chain resolves. IP address ranges (ip4:, ip6:) don't consume lookups.
SPF PermError (permanent error) is the result when the SPF evaluation encounters a condition it cannot handle, most commonly exceeding the 10 DNS lookup limit, but also a syntactically invalid record or a lookup that returns an error. Unlike SPF SoftFail or Fail, PermError is not a pass or a qualified fail; it means the check could not complete. Many receivers treat it as equivalent to SPF fail, which means SPF won't contribute to DMARC alignment for that message.
