SPF Records: The Complete Technical Guide
Alex Chen
December 29, 2025
Everything you need to know about Sender Policy Framework (SPF) records—from basic setup to advanced configurations.
Introduction
Sender Policy Framework (SPF) is an email authentication protocol designed to detect email spoofing. By publishing SPF records in DNS, domain owners can specify which mail servers are authorized to send email on behalf of their domain. This guide covers everything from basic SPF syntax to advanced configurations.
SPF Verification Flow
┌──────────────┐ ┌──────────────┐
│ Incoming │ │ Receiving │
│ Email │ │ Mail Server │
└──────┬───────┘ └──────┬───────┘
│ │
│ From: user@example.com │
│ (sent from IP: 192.168.1.100) │
│──────────────────────────────────>│
│ │
│ ┌───────┴───────┐
│ │ 1. Extract │
│ │ domain: │
│ │ example.com │
│ └───────┬───────┘
│ │
│ ┌───────┴───────┐
│ │ 2. DNS query │
│ │ TXT record │
│ └───────┬───────┘
│ │
│ ┌───────┴───────┐
│ │ 3. Check IP │
│ │ 192.168.1.100 │
│ │ against SPF │
│ └───────┬───────┘
│ │
│ ┌───────┴───────┐
│ │ 4. Result: │
│ │ Pass/Fail │
│ └───────────────┘How SPF Works
The SPF Verification Process
SPF Record Location
SPF records are published as TXT records in DNS:
$ dig TXT example.com +short
"v=spf1 mx ip4:192.168.1.0/24 include:_spf.google.com -all"SPF Syntax Deep Dive
Version Tag
Every SPF record must start with the version tag:
v=spf1Mechanisms
Mechanisms define which servers are authorized:
| Mechanism | Description | Example |
|---|---|---|
all | Matches everything | -all |
ip4 | IPv4 address/range | ip4:192.168.1.100 |
ip6 | IPv6 address/range | ip6:2001:db8::/32 |
a | Domain's A record | a:mail.example.com |
mx | Domain's MX servers | mx |
include | Include another SPF | include:_spf.google.com |
exists | Check if A record exists | exists:%{i}.bl.example.com |
ptr | Reverse DNS (deprecated) | ptr:example.com |
Qualifiers
Qualifiers define the result when a mechanism matches:
| Qualifier | Result | Meaning |
|---|---|---|
+ (default) | Pass | Authorized sender |
- | Fail | Unauthorized, reject |
~ | SoftFail | Probably unauthorized |
? | Neutral | No assertion |
Modifiers
| Modifier | Description | Example |
|---|---|---|
redirect | Use another domain's SPF | redirect=_spf.example.com |
exp | Custom failure message | exp=explain.example.com |
SPF Record Examples
Basic Configuration
v=spf1 mx -allOnly MX servers can send email.
Google Workspace
v=spf1 include:_spf.google.com ~allMicrosoft 365
v=spf1 include:spf.protection.outlook.com -allMultiple Services
v=spf1 mx ip4:203.0.113.0/24 include:_spf.google.com include:sendgrid.net -allComplex Enterprise Setup
v=spf1 mx
ip4:192.168.1.0/24
ip4:10.0.0.0/8
include:_spf.google.com
include:spf.protection.outlook.com
include:sendgrid.net
include:mailchimp.com
-allSPF Lookup Limit
The 10 DNS Lookup Limit
SPF has a hard limit of 10 DNS lookups. Exceeding this causes a PermError.
Mechanisms that count toward the limit:
Mechanisms that don't count:
Counting Lookups
v=spf1
include:_spf.google.com # 1 + nested lookups
include:sendgrid.net # 1 + nested lookups
mx # 1
a # 1
-allSolutions for Lookup Limit
#### 1. SPF Flattening
Convert includes to IP addresses:
# Before (uses lookups)
v=spf1 include:_spf.google.com -all
# After (no lookups)
v=spf1 ip4:172.217.0.0/16 ip4:209.85.128.0/17 ... -all#### 2. Subdomain Splitting
Use different subdomains for different services:
# Main domain
example.com TXT "v=spf1 mx include:_spf.google.com -all"
# Marketing subdomain
marketing.example.com TXT "v=spf1 include:sendgrid.net -all"SPF Results and Email Handling
| Result | Meaning | Recommended Action |
|---|---|---|
| Pass | IP authorized | Accept |
| Fail | IP not authorized | Reject |
| SoftFail | IP probably not authorized | Accept but flag |
| Neutral | No policy | Accept |
| None | No SPF record | Accept |
| PermError | Configuration error | Accept with caution |
| TempError | DNS timeout | Try later |
SPF Best Practices
1. Start with SoftFail
When first implementing SPF, use ~all to monitor without rejecting:
v=spf1 mx include:_spf.google.com ~allThen switch to -all once confident.
2. Keep Records Simple
# Good
v=spf1 include:_spf.google.com -all
# Avoid (too complex)
v=spf1 a mx ptr ip4:1.2.3.4 ip4:5.6.7.8 include:x include:y include:z -all3. Use Includes for Third-Party Services
Don't hardcode IPs from services that might change:
# Good
v=spf1 include:sendgrid.net -all
# Bad (IPs may change)
v=spf1 ip4:167.89.0.0/16 -all4. Document Your SPF Record
Keep a record of what each part means:
v=spf1
mx # Our mail servers
ip4:203.0.113.10 # Legacy server
include:_spf.google.com # Google Workspace
include:sendgrid.net # Transactional email
-all # Reject all othersTroubleshooting SPF
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Too many lookups | >10 DNS queries | Flatten or split |
| Multiple SPF records | Two TXT records | Merge into one |
| Syntax error | Invalid mechanism | Validate syntax |
| Missing include | Third-party service | Add include |
Diagnostic Tools
# Check SPF record
dig TXT example.com +short | grep spf
# Test SPF for specific IP
# Use online tools like mxtoolbox.comSPF Limitations
These limitations are why SPF is used alongside DKIM and DMARC.
Conclusion
SPF is a critical first layer of email authentication. Properly configured SPF records:
Start with a permissive policy, monitor results, then tighten restrictions over time.