What is SPF? A Beginner's Guide to Sender Policy Framework
SPF is the oldest and simplest of the three pillars of email authentication. It tells the world which mail servers are allowed to send email on behalf of your domain — and yet most SPF records you'll find in the wild contain at least one mistake.
What SPF actually is
Sender Policy Framework (SPF) is an email authentication standard defined in RFC 7208. In one sentence: SPF lets a domain owner publish a public list of the IP addresses that are authorised to send mail on behalf of that domain. When a receiving mail server gets a message claiming to be from you@example.com, it can look up the SPF record for example.com and check whether the IP that connected to it appears on that list.
SPF was designed to combat one specific kind of forgery: an attacker who wants to send mail from billing@your-bank.com can normally just type that into the MAIL FROM field of an SMTP conversation. SPF takes that ability away by tying the right to use a domain to a specific set of IP addresses.
How the check works
The SPF check happens at SMTP time, before the message body is even transferred. Here is the actual sequence:
- A sending server connects to the receiving server on port 25.
- The sending server issues
MAIL FROM:<alice@example.com>. - The receiving server takes the domain part —
example.com— and looks up itsTXTrecord(s) starting withv=spf1. - The receiver evaluates each mechanism in the SPF record against the connecting IP.
- If a mechanism matches, the receiver applies its qualifier (pass, fail, softfail, neutral) and stops evaluating.
The result — pass, fail, softfail, neutral, none, temperror or permerror — is then stored in the message's Authentication-Results header for downstream filters to use.
SPF record syntax
An SPF record is published as a DNS TXT record on the domain you want to authorise. A simple example:
example.com. IN TXT "v=spf1 ip4:192.0.2.10 include:_spf.google.com -all"
Reading this left to right:
v=spf1— the version tag. Always required, always exactly this string.ip4:192.0.2.10— this single IPv4 address is authorised.include:_spf.google.com— recursively include the SPF record published at_spf.google.com(this is what authorises Google Workspace to send for your domain).-all— if no earlier mechanism matched, the result is a hard fail. Anything that wasn't explicitly listed is unauthorised.
Mechanisms you'll actually use
ip4:andip6:— literal IP addresses or CIDR ranges.aanda:domain— the A record(s) of your domain (or another domain) are authorised.mxandmx:domain— the MX hosts of the domain are authorised. Useful when your inbound and outbound servers are the same.include:domain— pull in another domain's SPF record. This is how third-party senders (Mailchimp, Google, Microsoft) get authorised.exists:domainandptr— rarely used, andptris officially discouraged.
Qualifiers
+(pass) — the default, almost never written explicitly.-(fail) — reject this mail.~(softfail) — suspicious but not rejected outright.?(neutral) — no opinion, equivalent to no policy.
The qualifier on the trailing all is the most consequential character in the whole record. -all tells receivers to reject anything not listed; ~all says "treat it as suspicious." Most production senders should use -all once they are confident their record is complete.
The 10-lookup limit
This is the single most common SPF mistake we see in the field. RFC 7208 says that during evaluation, an SPF record may not cause more than ten DNS lookups in total. Every include, a, mx, exists and redirect counts; nested includes count too. If you exceed ten, the record returns permerror and the SPF check fails, regardless of which IP is connecting.
This trips people up because each major sender publishes its own multi-include SPF record. Combine Google, Mailchimp, SendGrid, Zendesk and your own outbound MTA and you are easily over twenty lookups before you realise it.
The fix is usually one of:
- Flatten the record by replacing
include:with literalip4:mechanisms (using a tool that resolves the includes for you). - Use SPF macros and an
exists:mechanism for very large CIDR sets. - Drop senders you no longer use.
Common mistakes
- Multiple SPF records. A domain may have only one
v=spf1record. Two records means an automaticpermerror. Merge them into a single record. - Forgetting the
allmechanism. Without it the record falls through to the default of "neutral", which provides no protection. - Using
?allin production. Equivalent to no policy. If you're going to publish SPF, mean it. - Authorising too much. A record like
v=spf1 +allsays "any IP on the internet may send for me" — which is exactly what an attacker wants. - Forgetting to include third-party senders. If your CRM sends emails on your behalf, its IPs (or include) must be in your SPF record.
- Confusing the envelope-from with the visible From. SPF authenticates the envelope-from (Return-Path), not the header From. This is exactly the gap DMARC was designed to close.
How to verify your SPF record
The easiest free tool is MXToolbox's SPF lookup. Type your domain in and you'll get the record, the resolved lookup count, and any syntax errors. From the command line:
dig +short TXT example.com | grep spf1
To test that your sending IP actually passes, send a test message to a Gmail address and inspect the original. The Authentication-Results header will read something like spf=pass smtp.mailfrom=example.com.
SPF on its own is not enough
SPF was a useful first step in 2003 but it has well-known limitations: it breaks on forwarding, it doesn't authenticate the visible From address, and a passing SPF check tells you nothing about whether the message body was tampered with. That's why a modern email setup combines SPF with DKIM and ties them together with DMARC. Treat SPF as the foundation, not the whole building.