SPF — Sender Policy Framework

RFC: 7208 (April 2014, supersedes RFC 4408) Layer: Authentication Lookup limit: 10 (DNS) + 2 (void) Last updated: May 2026 Reading time: 14 min
Definition

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.

# A typical SPF record example.com. IN TXT "v=spf1 include:_spf.google.com include:spf.mailwizz.example.com ip4:203.0.113.0/24 ~all" # Manual lookup from the command line $ dig +short TXT example.com "v=spf1 include:_spf.google.com include:spf.mailwizz.example.com ip4:203.0.113.0/24 ~all"

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:

QualifierMeaningSPF result for unmatched IPsRecommendation
+allPassPass (any IP authorized)Never use. Authorizes the entire internet to send as your domain.
?allNeutralNone / NeutralUseful only during initial discovery; receivers treat as weak signal.
~allSoftfailSoftfail (mark suspicious)Default during rollout and for most production deployments paired with strict DMARC.
-allHardfailFail (reject)Use only after DMARC reports confirm all legitimate senders are authorized for 2+ weeks.
SPF authenticates the envelope, not the visible From header. An attacker can pass SPF on a domain they control while putting your domain in the visible From: address — recipients won't see the discrepancy. SPF alone doesn't prevent spoofing of the user-visible From. This is why DMARC exists: it ties SPF (and DKIM) authentication results back to the domain in the From: header through alignment.

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:

MechanismLookup costNotes
ip4: / ip6:0Direct IP literal. No DNS query needed. Always free to use.
all0Default verdict mechanism. No lookup.
a1Resolves the A/AAAA record of the SPF domain (or specified domain).
mx1+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:1Tests whether a domain has an A record. Used in macro-based dynamic SPF.
ptr1+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.

ProviderInclude directiveTotal lookups consumedNested structure
Google Workspaceinclude:_spf.google.com4Top + 3 nested (_netblocks, _netblocks2, _netblocks3)
Microsoft 365 / Outlookinclude:spf.protection.outlook.com3Top + 2 nested regional includes
SendGridinclude:sendgrid.net2Top + 1 nested (u-spf)
Mailchimpinclude:servers.mcsv.net1Direct, no nesting (rare)
Mailguninclude:mailgun.org1Direct, no nesting
Postmarkinclude:spf.mtasv.net1Direct, no nesting
Amazon SESinclude:amazonses.com2Top + 1 nested (regional split)
HubSpotinclude:_spf.hubspotemail.net2Top + 1 nested
Salesforce / Marketing Cloudinclude:_spf.salesforce.com3Top + 2 nested (regional)
Zendeskinclude:mail.zendesk.com2Top + 1 nested
Klaviyoinclude:_spf.klaviyo.com1Direct, no nesting
Intercominclude:_spf.intercom.io1Direct, no nesting
The "5 ESP wall." The combination most organizations actually hit: Google Workspace (4) + Microsoft 365 (3) + SendGrid (2) + Salesforce (3) = 12 lookups. PermError. Even the simpler combo Google (4) + SendGrid (2) + Mailchimp (1) + HubSpot (2) + Amazon SES (2) = 11 lookups. The wall arrives faster than the count of providers suggests, because the top providers consume disproportionately. Most enterprises hit PermError silently after their 4th-5th ESP integration — and don't notice until a customer complains about missing receipts.

Visualizing the budget — typical "5 ESP" deployment

Google (4)
Microsoft 365 (3)
SendGrid (1+1)
Mailchimp (1)
Zendesk (2)
RFC 7208 limit ↓

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 mx mechanism on a domain whose MX records were removed
  • A ptr mechanism without a matching reverse DNS record
  • An a mechanism on a domain with no A/AAAA record
The "we removed the vendor but forgot the include" scenario. A common production failure: the marketing team stops using a third-party tool, but the SPF include is left in DNS. Months later, the vendor decommissions the SPF record entirely, the include returns NXDOMAIN, and over time more dead includes accumulate. Once you have 3+ void lookups, your SPF returns PermError on every evaluation. Audit your SPF record at least quarterly for stale includes.

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.

+ When it fits:
  • You require DMARC aspf=s (strict)
  • Your ESP roster is stable
  • You have automation watching for ESP IP changes
− Avoid when:
  • 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.

+ When it fits:
  • You have 5+ sending services
  • You use DMARC relaxed alignment (default)
  • You want a structural, low-maintenance solution
− Avoid when:
  • 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.

+ When it fits:
  • 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
− Avoid when:
  • 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)
Subdomains are usually the right answer. For organizations running 5+ sending services, the subdomain pattern produces a stable, low-maintenance solution that scales linearly with each new ESP. 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

# Apex domain SPF — minimal, only authorizes the apex itself example.com. IN TXT "v=spf1 ip4:203.0.113.10 ~all" # Marketing subdomain — full Mailchimp + SendGrid budget m.example.com. IN TXT "v=spf1 include:servers.mcsv.net include:sendgrid.net ~all" # Transactional subdomain — Postmark + Mailgun tx.example.com. IN TXT "v=spf1 include:spf.mtasv.net include:mailgun.org ~all" # Support subdomain — Zendesk + Intercom sup.example.com. IN TXT "v=spf1 include:mail.zendesk.com include:_spf.intercom.io ~all" # Each subdomain gets its OWN 10-lookup budget # DMARC relaxed alignment passes because all share organizational domain example.com

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

MAIL FROM: bounces@m.example.com From: noreply@example.com ✓ Aligned
MAIL FROM: bounces@example.com From: noreply@example.com ✓ Aligned
MAIL FROM: bounces@sendgrid.net From: noreply@example.com ✗ Not aligned

Strict alignment (aspf=s) — passes only on exact FQDN match

MAIL FROM: bounces@example.com From: noreply@example.com ✓ Aligned
MAIL FROM: bounces@m.example.com From: noreply@example.com ✗ Not aligned (subdomain mismatch)
Strict alignment is rarely worth it. The industry consensus, supported by deliverability teams at major receivers, is that 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

Symptom: bounce rate spike, complaint rate up, deliverability drop after no obvious change

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

Symptom: SPF "none" or "permerror" on receivers; DMARC consistently fails

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

Symptom: DNS query returns truncated record, syntax errors in SPF check tools

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

Symptom: SPF starts returning PermError without any active configuration change

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

Symptom: DMARC fails on legitimate ESP-sent mail despite SPF passing

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

Symptom: SPF fails for forwarded messages; DMARC pass-through depends entirely on DKIM

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 over include:. Because the IPs are dedicated and stable, we publish them directly in ip4: form. Lookup cost: zero. No risk of nested includes silently breaking the lookup budget.
  • ~all qualifier during the first 30 days, moving to -all only after DMARC aggregate reports confirm no legitimate sending sources are missing. Premature -all + p=reject is 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

# 1. Pull the current SPF record $ dig +short TXT example.com | grep spf1 "v=spf1 include:_spf.google.com include:spf.protection.outlook.com include:sendgrid.net ip4:203.0.113.0/24 ~all" # 2. Manually count direct mechanisms (excluding ip4/ip6/all) # include:_spf.google.com → 1 + nested # include:spf.protection.outlook.com → 1 + nested # include:sendgrid.net → 1 + nested # 3. Recursively resolve each include to count nested lookups $ dig +short TXT _spf.google.com "v=spf1 include:_netblocks.google.com include:_netblocks2.google.com include:_netblocks3.google.com ~all" # → 3 nested includes (4 total for Google) # 4. Use a tool for total verified count: # - PowerDMARC SPF Checker # - Mailhardener SPF audit # - dmarcian SPF Surveyor # - MxToolbox SPF tool

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.

  • 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 →