Sender Policy Framework (SPF) is a DNS record that tells receiving mail servers which IP addresses are allowed to send email on behalf of your domain. It's the first line of defence against spoofing — if a message claims to be from [email protected] but came from an IP not listed in your SPF record, the receiver knows the message is unauthorised.
It sounds simple, and it mostly is. But SPF has subtle rules around DNS lookup limits, alignment with DMARC, and the difference between hardfail and softfail that catch out almost everyone setting it up for the first time. This guide covers what SPF does, how to write a record correctly, and the mistakes to avoid.
What SPF Actually Does
An SPF record is a TXT record on the domain you send email from. It looks like this:
v=spf1 include:_spf.google.com include:sendgrid.net ~all
Reading left to right:
v=spf1— required version marker.include:_spf.google.com— authorise all IPs in Google's published SPF (i.e. Gmail/Workspace).include:sendgrid.net— authorise SendGrid's published IP range.~all— anything else: softfail (mark as suspicious but accept).
When a receiver gets a message from example.com, it looks up example.com's SPF record, retrieves the resulting list of allowed IPs, and checks whether the sender's IP is in the list. If yes: SPF passes. If no: SPF fails.
Mechanism Reference
The pieces you can use in an SPF record:
ip4:1.2.3.4— single IPv4 address.ip4:1.2.3.0/24— IPv4 range.ip6:2001:db8::/32— IPv6 range.a— authorise IPs found in the domain's A records.a:mail.example.com— authorise IPs from a specific A record.mx— authorise IPs from the domain's MX records.include:_spf.thirdparty.com— recursively include a third party's SPF record.exists:example.com— authorise if the named domain has an A record.redirect=other.com— replace this record with the one atother.com.~all— softfail anything not matched (the recommended default).-all— hardfail anything not matched (only safe once you're confident SPF is complete).?all— neutral — neither pass nor fail (essentially "we don't know").+all— pass everything. Never use this. It tells receivers any IP is authorised, defeating the entire point.
The 10-Lookup Limit
The single most important constraint in SPF: SPF records are limited to 10 DNS lookups when evaluated. include:, a:, mx:, exists:, redirect= all count toward the limit. Plain IP addresses (ip4:, ip6:) do not.
Hit the 11th lookup and the entire record returns "permerror" — which most receivers treat as a fail. This means a domain with too many includes in its SPF record will silently fail SPF for every receiver checking, even if the underlying authorisation should have been correct.
This is incredibly common because each include can recursively trigger more lookups:
include:_spf.google.com → 4 lookups (Google's record itself includes others)
include:sendgrid.net → 2 lookups
include:mailgun.org → 3 lookups
include:zendesk.com → 2 lookups
─────
11 lookups → permerror
Even a small business with Workspace + SendGrid + Mailgun is dangerously close to the limit.
How to Stay Under the Limit
Three strategies:
- Replace
include:with explicit IPs. Look up the IP ranges each provider currently publishes (e.g. SPF flatteners; Google publishes IPs at_netblocks.google.com) and add them asip4:/ip6:entries. Costs zero lookups. Costs maintenance — when a provider changes IPs, you have to re-flatten. - Use a hosted SPF flattener service. Several providers (e.g. EasyDMARC, Valimail, dmarcian) host a single
include:that auto-resolves to a flattened list of IPs. One include = one lookup, regardless of how many providers it covers. - Cut providers. If you have email going through three different transactional providers and a marketing tool and an ATS, consolidate. Each provider you remove is potentially 2–4 lookups freed.
Hardfail vs Softfail
The qualifier on all determines what receivers do with non-matching mail:
~all(softfail) — receiver should mark as suspicious but accept. Good default during initial deployment.-all(hardfail) — receiver should reject. Only use once you're confident every legitimate sender is in the record.?all(neutral) — no opinion. Useful only in transitional states; not a permanent setting.
If you set -all before you've verified your record covers every legitimate sender, real email starts bouncing and your team finds out from frustrated recipients. Start with ~all, run DMARC Dashboard for a few weeks to confirm only legitimate senders are passing, then upgrade to -all.
SPF Doesn't Cover Forwarding
SPF checks the IP that delivered the message. If a message is forwarded — through a mailing list, a vacation auto-forwarder, or an alias — the IP changes. The original sender's IP is no longer the one delivering, so SPF fails on the forwarded copy.
This is why SPF alone isn't enough. DMARC's "alignment" rules require either SPF or DKIM to pass, and DKIM survives forwarding (the signature is in the headers, not dependent on the connection IP). Pair SPF with DKIM and DMARC for full protection.
Common Mistakes
Multiple SPF records on one domain
An SPF record is a TXT record. Domains can have multiple TXT records, but RFC 7208 explicitly forbids multiple SPF records — receivers will treat the situation as permerror. Combine into a single record with multiple includes/IPs.
Missing the apex
SPF needs to be on the domain in the From address. example.com's SPF doesn't cover mail.example.com or vice versa. If you send from subdomains, each needs its own record (or an explicit redirect= rule).
Using +all
"Pass everything" defeats SPF entirely. We've audited domains where someone set +all while debugging, intending to revert later, and forgot. Always check.
Forgetting third-party senders
Marketing platforms (Mailchimp, Constant Contact), CRM platforms (HubSpot, Salesforce), helpdesk tools (Zendesk, Intercom), invoicing tools (Xero, Stripe), and survey tools all send email on your domain's behalf. Each one needs to be in your SPF record. Audit your tooling annually — it's almost always more than people expect.
Including obsolete providers
The opposite mistake: SPF records that include include: for providers you stopped using years ago. Each unnecessary include is a free lookup spent. Audit and prune annually.
Inconsistent host configuration
The SPF record is correct, but your mail server is sending from an IP not listed because of a configuration drift (a new outbound IP, a CDN/proxy change). Always test by sending mail from each path and checking the result in DMARC Dashboard.
Verifying Your SPF Record
Three tools:
- DMARC Dashboard — looks up SPF, DKIM, and DMARC for a domain in one go and flags issues.
- dig from the command line:
dig +short TXT example.comshows your raw record. - SPF lookup tools like dmarcian's SPF Surveyor count your lookups and flag overruns.
For real-world verification, send a message from each of your sending sources to an account at Gmail or Outlook (which both publish SPF results in headers) and check the Authentication-Results header for spf=pass.
The Practical Checklist
- Inventory every system that sends email on your domain's behalf. Don't miss invoicing, support, marketing, ATS, surveys.
- Check whether each has a published SPF include or specific IP requirements.
- Build the record: start with all required includes plus
~all. - Verify lookup count is under 10. If not, flatten or consolidate.
- Publish as a TXT record on the apex domain.
- Test from each sending source — verify
spf=passin the headers. - Run DMARC Dashboard to confirm everything's clean.
- Wait 2–4 weeks while monitoring DMARC reports for unexpected fails.
- Once confident, upgrade to
-all. - Re-audit annually as tooling changes.
SPF on its own won't stop spoofing — DMARC is what gives the policy teeth — but a clean SPF record is the foundation. Get it right and the rest of email authentication becomes much easier.