A complete reference to SPF (Sender Policy Framework) record syntax. Learn every mechanism, qualifier, and modifier — plus how to stay within the 10 DNS lookup limit.
SPF Record Structure
An SPF record is a DNS TXT record on your domain that lists the servers authorised to send email on your behalf. Every SPF record follows this structure:
- Must start with
v=spf1(exactly, case-sensitive) - Only ONE SPF record per domain (multiple records = permanent error)
- Maximum 255 characters per DNS TXT string (but can be split into multiple strings)
- Total record should stay under 512 bytes for UDP compatibility
- Mechanisms are evaluated left to right — first match wins
Qualifiers
Every mechanism can be prefixed with a qualifier that determines what happens when it matches:
| Qualifier | Meaning | Result | Usage |
|---|---|---|---|
+ |
Pass | Allow the email | Default if no qualifier specified. ip4:1.2.3.4 = +ip4:1.2.3.4 |
- |
Fail (hard) | Reject the email | Most commonly used on -all at the end of a record |
~ |
SoftFail | Accept but mark suspicious | Commonly used during transition: ~all. With DMARC, treated the same as fail. |
? |
Neutral | No opinion | Rarely used. Equivalent to having no SPF record for that mechanism. |
-all and ~all result in an SPF failure for DMARC alignment purposes. The distinction mainly matters for servers that don’t implement DMARC.
Mechanisms
ip4 and ip6 — IP Address Ranges
Match by the sender’s IP address. Does NOT count toward the 10 DNS lookup limit.
ip4:203.0.113.0/24 # IPv4 CIDR range (256 addresses)
ip6:2001:db8::1 # Single IPv6 address
ip6:2001:db8::/32 # IPv6 CIDR range
a — A/AAAA Record Lookup
Matches if the sender’s IP matches the A (or AAAA) record of the specified domain. Counts as 1 DNS lookup.
a:mail.example.com # Check a specific domain’s A record
a:example.com/24 # Match the /24 range around the A record IP
mx — MX Record Lookup
Matches if the sender’s IP matches any of the domain’s MX record addresses. Counts as 1 DNS lookup (plus 1 for each MX hostname resolved).
mx:example.com # Check another domain’s MX records
mx/24 # Match the /24 range around MX IPs
include — Include Another Domain’s SPF
Evaluates the SPF record of another domain. If that record produces a “pass”, this mechanism matches. Counts as 1 DNS lookup (plus any lookups within the included record).
include:spf.protection.outlook.com # Microsoft 365
include:sendgrid.net # SendGrid
include:servers.mcsv.net # Mailchimp
include triggers recursive lookups. include:_spf.google.com alone uses 3–4 lookups. This is the most common cause of exceeding the 10-lookup limit.
exists — Domain Existence Check
Passes if an A record exists for the specified domain (any IP). Used for advanced macro-based scenarios. Counts as 1 DNS lookup.
all — Catch-All
Matches everything. Always placed at the end of the record as the default rule.
~all # Soft fail: mark as suspicious but accept (common during transition)
?all # Neutral: no opinion on unmatched senders (rarely useful)
+all # Pass everything: defeats the purpose of SPF (never use this)
Modifiers
redirect
Replaces the entire SPF evaluation with another domain’s SPF record. Unlike include, it’s a full replacement — there’s no fallthrough. Counts as 1 lookup.
Only takes effect if no mechanisms in the record match. Cannot be used with all.
exp — Explanation
Specifies a domain whose TXT record contains a human-readable explanation for SPF failures. Rarely used in practice.
The 10 DNS Lookup Limit
RFC 7208 limits SPF evaluation to 10 DNS lookups. If your record exceeds this limit, the entire SPF check returns a permanent error (PermError) — which means SPF effectively doesn’t work at all.
What Counts as a DNS Lookup
include:a/a:mx/mx:exists:redirect=- Nested lookups within
include:
ip4:ip6:all- The initial SPF record lookup itself
Example: Counting Lookups
include:_spf.google.com # 1 + ~3 nested = 4 lookups
include:spf.protection.outlook.com # 1 + ~2 nested = 3 lookups
include:sendgrid.net # 1 + ~1 nested = 2 lookups
ip4:203.0.113.5 # 0 lookups (IP-based)
a # 1 lookup
-all
# Total: ~10 lookups — right at the limit!
SPF Flattening
If you’re hitting the 10-lookup limit, SPF flattening replaces include: mechanisms with the actual IP addresses they resolve to. This eliminates the DNS lookups but requires regular updates when providers change their IP ranges.
- IPs change without notice — you need automated re-flattening (weekly minimum)
- Records become much longer (many IP ranges)
- Harder to read and debug
- Consider SPF flattening services that automate this
Common Provider SPF Includes
| Provider | SPF Include | ~Lookups Used |
|---|---|---|
| Google Workspace | include:_spf.google.com |
3–4 |
| Microsoft 365 | include:spf.protection.outlook.com |
2–3 |
| SendGrid | include:sendgrid.net |
1–2 |
| Mailchimp | include:servers.mcsv.net |
1–2 |
| Amazon SES | include:amazonses.com |
1–2 |
| Zoho Mail | include:zoho.com |
2–3 |
| Postmark | include:spf.mtasv.net |
1 |
| Mailgun | include:mailgun.org |
1–2 |
| HubSpot | include:spf.hubspot.com |
1 |
Example SPF Records
Simple: Google Workspace Only
Common: Google + Marketing Platform
Complex: Multiple Services + Own Server
Domain That Doesn’t Send Email
Explicitly says “no server is authorised to send email for this domain.” Important for protecting parked domains.
Best Practices
- Use
ip4:/ip6:where possible to conserve DNS lookups - End with
-all(hard fail) once you’ve confirmed all legitimate senders - Use
~all(soft fail) during the transition period - Regularly audit your SPF record — remove old providers you no longer use
- Keep only ONE SPF record per domain
- Publish SPF records on all domains and subdomains — even those that don’t send email
- Use our Domain Checker to verify your SPF record and count lookups
For the bigger picture on how SPF fits with DKIM and DMARC, see SPF vs DKIM vs DMARC. For step-by-step setup, see What is SPF?.