SPF (Sender Policy Framework) is an email authentication protocol that allows domain owners to specify which mail servers are authorized to send email on behalf of their domain. SPF records are published as DNS TXT records.
v=spf1 [mechanisms] [modifiers]
- Version: Always starts with
v=spf1 - Mechanisms: Define which hosts are authorized to send mail
- Qualifiers: Prefix mechanisms to specify the result
- Modifiers: Provide additional information
# IPv4 address
v=spf1 ip4:192.168.1.1 ~all
# IPv4 subnet
v=spf1 ip4:192.168.0.0/16 ~all
# IPv6 address
v=spf1 ip6:2001:db8::1 ~all
# IPv6 subnet
v=spf1 ip6:2001:db8::/32 ~all
# A record of current domain
v=spf1 a ~all
# A record of specified domain
v=spf1 a:mail.example.com ~all
# MX records of current domain
v=spf1 mx ~all
# MX records of specified domain
v=spf1 mx:example.com ~all
# Include another domain's SPF record
v=spf1 include:_spf.google.com ~all
# Check if domain exists
v=spf1 exists:%{i}.whitelist.example.com ~all
# Allow all (NOT RECOMMENDED)
v=spf1 +all
# The current domain itself
v=spf1 ptr ~all # DEPRECATED - DO NOT USE
Each mechanism can be prefixed with a qualifier:
+(Pass): Allow the host (default if omitted)-(Fail): Reject the host~(SoftFail): Mark as suspicious but don't reject?(Neutral): No policy statement
v=spf1 +ip4:192.168.1.0/24 -ip4:192.168.1.99 ~all
Redirects SPF checks to another domain:
v=spf1 redirect=_spf.example.com
Provides explanation for failures:
v=spf1 mx -all exp=explain.example.com
Begin with a soft fail to monitor before enforcing:
# Initial deployment
v=spf1 include:_spf.google.com include:mail.protection.outlook.com ~all
# After validation
v=spf1 include:_spf.google.com include:mail.protection.outlook.com -all
Minimize DNS lookups and complexity:
# GOOD: Direct IP specification
v=spf1 ip4:192.0.2.0/24 ip4:198.51.100.0/24 -all
# BAD: Too many includes
v=spf1 include:provider1.com include:provider2.com include:provider3.com include:provider4.com include:provider5.com -all
Be as specific as possible with IP ranges:
# GOOD: Specific subnet
v=spf1 ip4:192.0.2.0/28 -all
# BAD: Overly broad
v=spf1 ip4:192.0.0.0/8 -all
When using includes, understand the chain:
# Main domain
example.com: v=spf1 include:_spf.example.com -all
# Included record
_spf.example.com: v=spf1 ip4:192.0.2.0/24 ip4:198.51.100.0/24 ~all
Add comments in DNS management system:
# Production mail servers (datacenter 1 and 2) + Google Workspace
v=spf1 ip4:192.0.2.0/24 ip4:198.51.100.0/24 include:_spf.google.com -all
SPF has a hard limit of 10 DNS lookups. Mechanisms that count:
include:amxptr(deprecated)exists:redirect=
# BAD: May exceed lookup limit
v=spf1 include:provider1.com include:provider2.com mx a -all
# GOOD: Use IP addresses when possible
v=spf1 ip4:192.0.2.0/24 include:_spf.google.com -all
In addition to the 10-lookup limit, there is a separate limit of 2 "void" lookups. A void lookup occurs when a DNS query for a mechanism (like include: or exists:) returns no records (an NXDOMAIN or NODATA response). Exceeding this limit will cause a PermError, invalidating the SPF check. This often happens with misspelled domains or when a third-party service is removed without updating the SPF record.
Only ONE SPF record per domain is allowed:
# WRONG: Two separate TXT records
example.com TXT "v=spf1 include:_spf.google.com ~all"
example.com TXT "v=spf1 include:mail.protection.outlook.com ~all"
# CORRECT: Combined into one record
example.com TXT "v=spf1 include:_spf.google.com include:mail.protection.outlook.com ~all"
Common syntax mistakes:
# WRONG: Missing version
"ip4:192.0.2.1 -all"
# WRONG: Wrong version
"v=spf2 ip4:192.0.2.1 -all"
# WRONG: Invalid mechanism
"v=spf1 ipv4:192.0.2.1 -all"
# CORRECT
"v=spf1 ip4:192.0.2.1 -all"
Be careful with DNS notation:
# WRONG: Trailing dot in include
v=spf1 include:_spf.google.com. -all
# CORRECT: No trailing dot
v=spf1 include:_spf.google.com -all
Avoid circular include references:
# Domain A includes Domain B
domainA.com: v=spf1 include:domainB.com -all
# Domain B includes Domain A (CIRCULAR!)
domainB.com: v=spf1 include:domainA.com -all
Note: Circular references can lead to infinite loops and SPF validation failures.
# Domain that never sends email
v=spf1 -all
# One dedicated mail server
v=spf1 ip4:192.0.2.1 -all
# Google Workspace + Marketing platform
v=spf1 include:_spf.google.com include:spf.mandrillapp.com -all
# Include parent domain's mail servers
v=spf1 include:example.com -all
Ensure proper formatting:
$ dig +short TXT example.com | grep spf1
"v=spf1 include:_spf.google.com -all"Manually trace through includes to count lookups.
Use SPF validators to check:
- Syntax validity
- DNS lookup count
- Include chain resolution
Check SPF results in email headers:
Received-SPF: pass (google.com: domain of sender@example.com designates 192.0.2.1 as permitted sender)
- Single string: 255 characters max
- Multiple strings: Can be concatenated
- Total: Varies by DNS provider (typically 4096 characters)
# Split into multiple strings (automatically concatenated)
example.com TXT "v=spf1 "
"ip4:192.0.2.0/24 "
"ip4:198.51.100.0/24 "
"include:_spf.google.com "
"-all"
-
Phase 1: Deploy with
?all(neutral)v=spf1 include:_spf.google.com ?all -
Phase 2: Move to
~all(soft fail)v=spf1 include:_spf.google.com ~all -
Phase 3: Enforce with
-all(hard fail)v=spf1 include:_spf.google.com -all
# Before adding new service
v=spf1 include:_spf.google.com -all
# Temporarily soften while testing
v=spf1 include:_spf.google.com ~all
# Add new service
v=spf1 include:_spf.google.com include:amazonses.com ~all
# Re-harden after validation
v=spf1 include:_spf.google.com include:amazonses.com -all
- Check DNS propagation: Records may take time to update
- Verify IP addresses: Ensure sending IPs match SPF record
- Review include chains: Included records may have changed
- Check for typos: Even small errors invalidate the record
- Monitor if provider IPs change
- Check if includes are hitting lookup limits
- Verify no duplicate or conflicting records
- Reduce DNS lookups by using IP addresses
- Consolidate multiple includes where possible
- Consider dedicated SPF subdomains for organization
SPF is a critical email authentication mechanism that requires careful planning and maintenance. Key takeaways:
- Always start with
v=spf1 - Keep under 10 DNS lookups
- Use specific IP ranges when possible
- Test thoroughly before enforcing with
-all - Monitor and maintain records as infrastructure changes
- Combine with DKIM and DMARC for complete email authentication