On this page
Sender Policy Framework (SPF)
Publish a single, bounded SPF policy that authorizes legitimate envelope senders without exceeding the 10-DNS-lookup limit or using overly permissive qualifiers.
What it is
Sender Policy Framework (SPF), specified in RFC 7208, is a DNS-based authentication protocol that enables domain owners to specify which mail transfer agents (MTAs) and IP addresses are authorized to send email on behalf of their domain.
SPF operates during the initial SMTP handshake and validates the envelope sender (the MAIL FROM or Return-Path identity), as well as the HELO/EHLO domain name presented by the connecting mail server.
example.com. IN TXT "v=spf1 ip4:198.51.100.0/24 include:_spf.google.com -all"
An SPF record is published as a standard DNS TXT record at the root of the sending domain. It consists of the v=spf1 prefix followed by ordered mechanisms (ip4, ip6, a, mx, include) and a terminating qualifier (-all for hardfail, ~all for softfail, or ?all for neutral).
Why it matters
- Spoofing and Phishing Prevention: Without SPF, any SMTP server on the internet can claim any domain in the envelope sender address. SPF provides receiving mail servers with an authoritative, cryptographic-free mechanism to verify IP authorization before accepting message payloads.
- DMARC Compliance: DMARC (RFC 7489) requires either SPF or DKIM to achieve authentication and domain alignment with the visible
From:header. A properly configured SPF policy is one of the two foundational pillars required for inbox placement at major mailbox providers (Google, Yahoo, Microsoft 365, Apple Mail). - Early Rejection of Malicious Mail: Because SPF is evaluated during the SMTP transaction at
MAIL FROMtime, receiving mail servers can reject fraudulent messages with a550 5.7.1error code before downloading the message body, saving bandwidth and compute.
How to implement
1. Publish exactly one SPF record per domain.
Never publish multiple TXT records starting with v=spf1. Multiple records cause an immediate PermError (permanent error) on receiving mail servers, invalidating SPF authentication entirely:
; CORRECT: Single unified SPF record
example.com. IN TXT "v=spf1 ip4:198.51.100.10 include:_spf.mailgun.org include:_spf.google.com -all"
; WRONG: Multiple SPF records cause PermError
example.com. IN TXT "v=spf1 include:_spf.google.com ~all"
example.com. IN TXT "v=spf1 include:_spf.mailgun.org ~all"
2. Strictly adhere to the 10-DNS-lookup limit.
RFC 7208 §4.6.4 limits the number of DNS-querying mechanisms (include, a, mx, ptr, exists, redirect) to a maximum of 10 lookups per evaluation. Exceeding 10 lookups results in a PermError and failed authentication:
- Count nested
include:lookups recursively (for example,include:_spf.google.comconsumes 3 lookups internally). - Replace
aandmxmechanisms with directip4:orip6:CIDR blocks where static server IPs are known. - Avoid deprecated mechanisms like
ptr.
3. Choose the appropriate policy qualifier.
-all(Hardfail): The standard production configuration. Explicitly states that any IP address not listed is unauthorized and should be rejected.~all(Softfail): Accepts messages from unlisted IPs but tags them as suspicious. Recommended during initial rollout while auditing all third-party sending services (CRM, transactional ESPs, helpdesk platforms).+all(Pass all): Never use+allin production. It authorizes every IP address on the internet to send mail as your domain.
4. Publish defensive SPF records for non-sending domains. Every park domain, redirect domain, and internal subdomain that does not send email must publish a defensive “null” SPF record to block spoofers:
non-sending.example.com. IN TXT "v=spf1 -all"
Common mistakes
- Exceeding the 10-DNS-Lookup Limit: Chaining multiple third-party marketing and CRM platforms (HubSpot, Salesforce, Zendesk, Mailchimp) frequently pushes the lookup count past 10, silently breaking SPF for all recipients.
- Forgetting Subdomains: SPF records do not automatically inherit down to subdomains. If mail is sent with
MAIL FROM: bounces.marketing.example.com, an SPF record must be published directly atbounces.marketing.example.com. - Using Deprecated
SPFResource Records: Do not use the obsolete DNS record type 99 (SPF). Modern resolvers only query DNSTXTrecords. - Ignoring Void DNS Lookups: RFC 7208 §4.6.4 limits lookups that return
NXDOMAINor no records to a maximum of 2. A single staleinclude:pointing to a deleted domain can trigger a void lookup error.
Verification
1. Query the live SPF record using dig:
dig +short TXT example.com | grep "v=spf1"
2. Count total recursive DNS lookups: Check nested includes to ensure the total mechanism count remains well below 10:
# Check lookup resolution chain
dig +short TXT _spf.google.com
3. Inspect delivered message headers:
Send a test message to an external mailbox and verify the Authentication-Results and Received-SPF headers:
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of [email protected] designates 198.51.100.10 as permitted sender) [email protected];
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.com
Received-SPF: pass (google.com: domain of [email protected] designates 198.51.100.10 as permitted sender) client-ip=198.51.100.10;