Sender Policy Framework — a DNS-based authentication mechanism by which a domain owner publishes the list of IP addresses authorized to send email on behalf of the domain. Receiving mail servers query the SPF TXT record during the SMTP transaction (specifically against the MAIL FROM domain, also called Return-Path) and accept or reject the connection based on whether the sending IP appears in the authorized list. SPF answers a single question: "Is this IP authorized to send mail using this Return-Path domain?" Nothing more.
How SPF works in the SMTP transaction
SPF runs at SMTP envelope time, before any message data is exchanged. The receiving server, after the connecting client issues MAIL FROM:<sender@example.com>, performs a DNS TXT lookup against example.com to retrieve the SPF record. The record is a single string starting with v=spf1, followed by mechanisms that authorize specific IPs or delegate authorization to other domains, terminated by an all mechanism that defines the default action for unmatched IPs.
The receiving server reads the record left-to-right and stops at the first match. If the connecting IP is in _spf.google.com's allowed range, SPF returns pass. If it falls through to ~all, SPF returns softfail. The qualifier on all determines the default verdict for unmatched IPs:
| Qualifier | Meaning | SPF result for unmatched IPs | Recommendation |
|---|---|---|---|
+all | Pass | Pass (any IP authorized) | Never use. Authorizes the entire internet to send as your domain. |
?all | Neutral | None / Neutral | Useful only during initial discovery; receivers treat as weak signal. |
~all | Softfail | Softfail (mark suspicious) | Default during rollout and for most production deployments paired with strict DMARC. |
-all | Hardfail | Fail (reject) | Use only after DMARC reports confirm all legitimate senders are authorized for 2+ weeks. |
The 10 DNS lookup limit — why it matters and how to count
RFC 7208 section 4.6.4 mandates that receiving servers MUST NOT perform more than 10 DNS lookups while evaluating an SPF record. Exceeding the limit produces a PermError (permanent error), which fails SPF authentication completely — not partially. Every email from your domain loses SPF authentication when this happens, regardless of which IP is sending. PermError also breaks DMARC pass-through if your DMARC policy depends on SPF rather than DKIM.
The limit exists for a real reason: SPF evaluation runs synchronously during SMTP, and unbounded recursive lookups would create a DNS amplification vector that malicious actors could weaponize against receiving infrastructure. The 10-lookup cap protects DNS resolvers from abuse — but it also creates the single most common SPF failure mode in production.
Mechanism cost — what counts and what doesn't
Not every SPF mechanism consumes a lookup. The cost varies by mechanism type:
| Mechanism | Lookup cost | Notes |
|---|---|---|
ip4: / ip6: | 0 | Direct IP literal. No DNS query needed. Always free to use. |
all | 0 | Default verdict mechanism. No lookup. |
a | 1 | Resolves the A/AAAA record of the SPF domain (or specified domain). |
mx | 1+ | 1 lookup for MX records, plus 1 lookup per MX hostname (capped at 10 A/AAAA results per MX). |
include: | 1+ | 1 lookup at your level + the entire cost of the included record's nested lookups. Most expensive in practice. |
exists: | 1 | Tests whether a domain has an A record. Used in macro-based dynamic SPF. |
ptr | 1+ | Reverse DNS lookup. Strongly discouraged by RFC 7208 due to performance, reliability, and security issues. |
redirect= | 1+ | Modifier (not mechanism). Replaces the entire record with another. Counts the same as include for lookup budget. |
ESP-by-ESP lookup cost map (the chart most guides skip)
The reason organizations hit the 10-lookup wall faster than expected is that ESP includes are rarely "1 lookup." Each major email provider's include: resolves to nested includes within their own infrastructure. Below is the actual cost of common ESP includes as of May 2026, verified by recursive DNS resolution against each provider's public SPF record. Treat these as moving targets — they change.
| Provider | Include directive | Total lookups consumed | Nested structure |
|---|---|---|---|
| Google Workspace | include:_spf.google.com | 4 | Top + 3 nested (_netblocks, _netblocks2, _netblocks3) |
| Microsoft 365 / Outlook | include:spf.protection.outlook.com | 3 | Top + 2 nested regional includes |
| SendGrid | include:sendgrid.net | 2 | Top + 1 nested (u-spf) |
| Mailchimp | include:servers.mcsv.net | 1 | Direct, no nesting (rare) |
| Mailgun | include:mailgun.org | 1 | Direct, no nesting |
| Postmark | include:spf.mtasv.net | 1 | Direct, no nesting |
| Amazon SES | include:amazonses.com | 2 | Top + 1 nested (regional split) |
| HubSpot | include:_spf.hubspotemail.net | 2 | Top + 1 nested |
| Salesforce / Marketing Cloud | include:_spf.salesforce.com | 3 | Top + 2 nested (regional) |
| Zendesk | include:mail.zendesk.com | 2 | Top + 1 nested |
| Klaviyo | include:_spf.klaviyo.com | 1 | Direct, no nesting |
| Intercom | include:_spf.intercom.io | 1 | Direct, no nesting |
Visualizing the budget — typical "5 ESP" deployment
Total: 12 lookups → PermError. SPF authentication fails for all email from this domain.
The void lookup limit (the one nobody mentions)
RFC 7208 imposes a separate limit that most practitioners miss: the void lookup limit. A void lookup is a DNS query that returns NXDOMAIN or an empty result set. The cap is 2 void lookups per evaluation. Exceeding it returns PermError even when your total lookup count remains under 10.
Common causes of void lookups:
- An
include:pointing to a domain that no longer exists (vendor decommissioned, typo) - An
mxmechanism on a domain whose MX records were removed - A
ptrmechanism without a matching reverse DNS record - An
amechanism on a domain with no A/AAAA record
Solving the lookup limit — flattening vs subdomains vs macros
Three structural fixes exist when you hit the lookup ceiling. The right choice depends on whether you need DMARC strict alignment, how often your ESP roster changes, and your tolerance for ongoing maintenance. The most common mistake is reaching for flattening when subdomains would solve the problem with less operational burden.
SPF Flattening Caution
Replace include: mechanisms with their resolved ip4: / ip6: addresses. Total lookup count drops to zero — but the record becomes static, breaking when ESPs change IPs.
- You require DMARC
aspf=s(strict) - Your ESP roster is stable
- You have automation watching for ESP IP changes
- You don't have monitoring for ESP IP changes
- Your providers update IPs frequently (Google, Office 365)
- Your record would exceed 255-char DNS string segments often
SPF Subdomains Recommended
Delegate each ESP to its own subdomain (m.example.com, support.example.com) so each subdomain gets its own 10-lookup budget. The visible From: can still use the apex domain.
- You have 5+ sending services
- You use DMARC relaxed alignment (default)
- You want a structural, low-maintenance solution
- You require DMARC
aspf=s(strict alignment) — subdomains break this by definition - You can't configure ESPs to use separate Return-Path subdomains
SPF Macros Expert
Use SPF macro syntax (%{l}, %{s}, %{i}) to dynamically construct includes per-recipient, per-sender, or per-IP. Keep one short SPF record while authorizing different ESPs for different addresses.
- You need per-local-part authorization (
support@uses Zendesk, marketing uses Mailchimp, etc.) - You have DNS infrastructure to maintain dynamic records
- You have specific security requirements that subdomains can't address
- You don't have dedicated DNS engineering
- You need 100% receiver compatibility (some receivers ignore macros)
- You can solve the problem with subdomains (most cases)
m1.example.com for transactional, m2.example.com for marketing, m3.example.com for support tools — each subdomain gets its own 10-lookup budget, and DMARC relaxed alignment continues to pass because all subdomains share the same organizational domain. Reach for flattening or macros only when subdomains can't solve your specific case.
The subdomain pattern in practice
SPF and DMARC alignment — the part that bites
An email can pass SPF authentication and still fail DMARC. This is the most common cause of unexpected DMARC failures during enforcement rollout, and it's the consequence of how SPF authenticates the envelope (MAIL FROM) while DMARC checks the visible header (From:).
DMARC requires that the SPF-authenticated domain aligns with the From: header domain. The alignment mode is controlled by the aspf tag in your DMARC record:
Relaxed alignment (aspf=r, default) — passes if organizational domains match
Strict alignment (aspf=s) — passes only on exact FQDN match
aspf=s provides no measurable security improvement over aspf=r while making configuration significantly more fragile. Common scenarios that break under strict: any ESP using a custom Return-Path subdomain, Google Workspace alias domains (Google forces primary domain in Return-Path), forwarders that rewrite envelope sender. Default to aspf=r unless you have a specific compliance requirement that demands strict.
Forwarding remains the persistent thorn in SPF alignment regardless of mode. When a recipient forwards an email through their server, the new outbound connection comes from the forwarder's IP — not from your authorized list. SPF fails. The fix isn't tightening SPF; the fix is ensuring DKIM is properly configured, since DKIM signatures survive forwarding (DKIM signs the message body, not the envelope). Most operators rely on DKIM for DMARC pass-through specifically because of this — and because DMARC passes if either SPF or DKIM aligns.
Common SPF failure modes in production
Silent PermError after ESP onboarding
New ESP integration pushes lookup count past 10. SPF returns PermError on every evaluation. DMARC reporting flags it but nobody checks until a customer complains. Fix: audit lookup count after every DNS change.
Multiple SPF records on the same domain
Two TXT records both starting with v=spf1. RFC 7208 forbids this — receivers MUST treat as PermError. Fix: consolidate to a single SPF record. Multiple authorized sources go in includes, not separate records.
String length over 255 chars in single TXT segment
DNS TXT records support 255 char segments; longer records must split into multiple quoted strings within the same record. Many DNS providers don't expose this clearly. Fix: use SPF flattening to ip4 ranges (CIDR-aggregated) to shorten, or switch to subdomains.
Void lookup accumulation from dead vendors
Stale include: mechanisms pointing to vendors that decommissioned their SPF. Once 3+ void lookups accumulate, SPF fails. Fix: quarterly audit of every include — remove anything not actively used.
Custom Return-Path with strict alignment
ESP uses bounces.esp.com as Return-Path; aspf=s requires example.com. SPF passes, DMARC fails alignment. Fix: switch to aspf=r, or configure ESP to use a subdomain of your domain as Return-Path (when supported — Postmark, Mailgun, Mailchimp all support this).
Forwarding breakage
Recipient sets up forwarding from your-recipient@gmail.com to their own server. Forwarder's IP isn't in your SPF. Fix: ensure DKIM is configured correctly so DMARC can pass via DKIM alignment. ARC helps when forwarders implement it.
SPF in Cloud Server for Email's managed infrastructure
For clients on managed PowerMTA + MailWizz infrastructure, SPF setup is part of the day 1-3 onboarding sequence. The pattern we use across most accounts:
- Subdomain delegation by default. A new client typically gets a sending subdomain (e.g.,
m.clientdomain.com) delegated via NS records to our DNS, with SPF authorizing only the dedicated IPs allocated to that account. The apex domain SPF stays under the client's control and reflects only their corporate sending sources. - Direct
ip4:mechanisms overinclude:. Because the IPs are dedicated and stable, we publish them directly inip4:form. Lookup cost: zero. No risk of nested includes silently breaking the lookup budget. - ~all qualifier during the first 30 days, moving to
-allonly after DMARC aggregate reports confirm no legitimate sending sources are missing. Premature-all+p=rejectis the most common cause of legitimate mail loss during enforcement rollout. - Quarterly SPF audits on every domain in our managed portfolio, looking for stale includes, void lookup accumulation, lookup count drift, and TXT record fragmentation across multiple records.
Clients with multiple ESPs already in place before joining typically come with SPF records already at or over the 10-lookup limit. The first 14 days of onboarding usually include a flattening or subdomain restructure to bring the record into compliance. We provide the audit, document the recommended structure, and execute the DNS changes coordinated with the client's DNS administrator.
Auditing your current SPF — practical workflow
For programmatic auditing inside CI pipelines, the spfcheck CLI (Python) or checkspf (Go) both provide exit codes suitable for failing builds when a deployment would push a domain over the lookup limit.
Related concepts
- DMARC — the policy layer that uses SPF (and DKIM) authentication results plus alignment to decide what receivers should do with failing mail.
- DKIM — cryptographic signature on outbound mail that survives forwarding, complementing SPF's envelope-based authentication.
- Sender Reputation — SPF authentication is one input to overall sender reputation at major receivers, not the only one.
- MTA-STS — transport-layer security policy, separate from but often deployed alongside SPF/DKIM/DMARC.
- BIMI — brand logo display, requires DMARC enforcement (which requires functional SPF and DKIM). (Coming soon)
Frequently asked questions
What is the SPF 10 DNS lookup limit?
RFC 7208 mandates that receiving servers MUST NOT perform more than 10 DNS lookups while evaluating an SPF record. Mechanisms that count: include, a, mx, ptr, exists, and the redirect modifier. Mechanisms that don't count: ip4, ip6, all. Exceeding the limit returns PermError, which fails SPF authentication completely — not partially. There's a separate 'void lookup' limit of 2: lookups that return NXDOMAIN or empty results count against this even if you stay under the 10-lookup ceiling.
Does an include count as one lookup or many?
An include counts as 1 lookup at your level — but it inherits the lookup count of the included record. include:_spf.google.com is famously 4 lookups total because Google's record contains 3 additional nested includes (_netblocks, _netblocks2, _netblocks3). This is why it's easy to exceed 10 with only 3-4 ESPs: each provider's SPF is rarely just 1 lookup.
What's the difference between SPF flattening and SPF subdomains?
Flattening replaces include mechanisms with the resolved ip4/ip6 addresses, dropping lookup count to zero but creating a static record that breaks when vendors change IPs. Subdomains delegate each ESP to its own subdomain (m1.example.com for Mailgun, m2.example.com for SendGrid), so each subdomain has its own 10-lookup budget. Subdomains are the recommended structural fix for organizations with 5+ sending services because they don't require active maintenance. Flattening is the right choice when DMARC strict alignment is required — subdomains break aspf=s.
How does SPF interact with DMARC alignment?
SPF authenticates the SMTP MAIL FROM domain (also called Return-Path). DMARC then checks whether that authenticated domain aligns with the From: header domain visible to recipients. Relaxed alignment (default, aspf=r) considers them aligned if they share the same organizational domain — m.example.com aligns with example.com. Strict alignment (aspf=s) requires exact FQDN match. SPF can pass authentication but fail DMARC alignment, which is the most common cause of unexpected DMARC failures during enforcement rollout.
What does SPF PermError mean operationally?
PermError is a permanent SPF failure caused by a structural issue in your record: too many DNS lookups (>10), too many void lookups (>2), syntax errors, or invalid mechanism use. Critically, PermError fails SPF for ALL email from your domain, not just for the connection that triggered the count. It also fails any DMARC policy that depends on SPF authentication — so a single new ESP push can silently break authentication for your entire domain. Major receivers (Gmail, Microsoft, Yahoo) treat PermError as failure, not soft-fail.
Should SPF use ~all (softfail) or -all (hardfail)?
Use ~all (softfail) during initial rollout and any period where your sending source list might be incomplete. Use -all (hardfail) once you've confirmed via DMARC aggregate reports for at least 2 weeks that all legitimate sending sources are authorized. The practical difference: ~all tells receivers "this might not be us, mark suspicious"; -all tells receivers "this is definitely not us, reject". The real authority for handling SPF failures comes from your DMARC policy (p=quarantine or p=reject), so ~all + p=reject is more common than -all + p=none in mature deployments.
Are SPF macros worth using in production?
Rarely, despite being widely supported by MTAs. Macros let you build dynamic SPF records that vary by sender IP, local part, or HELO — useful for restricting third-party services to specific addresses (e.g., support@yourdomain.com can use Zendesk but the rest of your domain cannot). The trade-off is operational complexity: requires custom DNS infrastructure, isn't 100% supported by all receivers, and easy to misconfigure. For most organizations, subdomains solve the same scaling problem with less complexity. Consider macros only when you have specific per-address authorization requirements that subdomains can't address.
How do I check my current SPF lookup count?
Use any of these tools that recursively resolve includes and report the total: PowerDMARC SPF Checker, dmarcian SPF Surveyor, EasyDMARC SPF lookup, MxToolbox SPF tool, or Mailhardener SPF audit. From the command line: dig +short TXT example.com extracts your record, but counting nested includes manually is error-prone. The tool-based check should be done after every DNS change involving sending sources, not just when something breaks. Schedule a monthly audit even when you haven't made changes — ESPs occasionally add nested includes to their own records, silently consuming your budget.
Need an SPF audit on your sending domains?
Cloud Server for Email's onboarding includes a complete SPF audit across all your sending domains: lookup count, void lookup detection, alignment validation against DMARC policy, and structural recommendations. We've untangled SPF records for clients running 8+ concurrent ESPs.
Talk to engineering →