SPF records: setup, the 10-lookup limit, and common errors
How SPF lists the servers allowed to send a domain’s mail, and how to fix a missing record, too many DNS lookups, or a missing include.
SPF is a DNS record that lists the servers allowed to send mail for your domain. A receiving server checks the address of the server that sent a message against that list, and the message passes or fails.
SPF checks the bounce address (the envelope sender), not the From address people see. DMARC counts an SPF pass only when the bounce address uses your domain or a subdomain of it. DKIM is the other way to pass.
What SignalDNS checks
We read the TXT records on the domain and pick out the ones that start with v=spf1. Exactly one is expected. We check each term against the syntax in RFC 7208, then follow every include and redirect, and the ones inside those, as a receiver would.
On the way, we count the terms that cost a DNS lookup: include, a, mx, ptr, exists, and redirect. RFC 7208 allows 10 in total, across every record SPF reaches, not 10 per record. ip4, ip6, and all cost nothing. If two includes share a third record, its lookups count twice, as they do for receivers.
We report the all term that applies, which can come from a record you redirect to, and how many of the 10 lookups SPF uses.
What an SPF record looks like
example.com. TXT "v=spf1 include:_spf.google.com ip4:192.0.2.10 ~all"
v=spf1must come first.include:adds another domain’s list, usually a provider’s. It costs one lookup, plus every lookup inside that record.ip4:andip6:list addresses or ranges directly, and cost no lookups.aandmxallow the domain’s own web or mail servers. Each costs a lookup.~allor-allat the end tells receivers what to do with every other server.redirect=hands the whole check to another domain’s record. It’s ignored if the record has its ownall.
There’s only one SPF record per name. To add a service, add its include to the record you have.
There’s no SPF record
No TXT record on the domain starts with v=spf1. Receivers can’t tell which servers may send for it, so SPF can’t help them spot forged mail, and DMARC has only DKIM to go on. SignalDNS marks this as needing attention.
How to fix it: add one TXT record on the domain itself (often entered as @) that lists the services that send your mail. Your provider’s guide gives its include. For Google Workspace alone:
v=spf1 include:_spf.google.com ~all
If the domain never sends mail, publish a record that allows no one:
v=spf1 -all
SPF is broken
Receivers can’t evaluate the record, so SPF returns a permanent error (permerror) for every message instead of a pass. DMARC then has only DKIM to go on. SignalDNS marks this as a problem. The causes we report:
- More than one SPF record. RFC 7208 makes two
v=spf1records on one name an error. Merge them into one, with onev=spf1at the start and oneallat the end. - A term that isn’t valid, such as a typo like
inlcude:, aninclude:with no domain, or anip4:value that isn’t an IPv4 address. One bad term breaks the whole record. - A loop. A record includes, directly or through others, a record that led to it.
- An include with no SPF record. RFC 7208 makes an include or redirect to a domain without an SPF record an error, not a skip.
How to fix it: correct the record so it has one v=spf1, valid terms, and includes that exist. The same rules apply to records you include, and we name the record with the mistake. If it’s another provider’s, check the include’s spelling against their guide, or remove it if you no longer use the service.
SPF has too many DNS lookups
SPF needs more than 10 DNS lookups. RFC 7208 has receivers stop there and return permerror, so SPF fails for all your mail, including mail from servers you list. SignalDNS marks this as a problem.
Each include counts, and so does everything inside it. One provider’s include can use several lookups on its own.
How to fix it:
- Remove includes you don’t use, such as services you’ve left. DMARC reports show which services really send your mail.
- Replace
a,mx, andptrwith addresses. For servers you run yourself,ip4:andip6:cost nothing. RFC 7208 says not to useptrat all. - Move a sender to a subdomain. If a service lets you set its bounce domain, such as
bounce.example.com, its SPF goes on that subdomain, with its own 10 lookups. - Flatten only as a last step. Flattening replaces an include with the addresses it lists today. That saves lookups, but when the provider changes its addresses, your mail fails SPF. If you flatten, use a tool that keeps the addresses up to date.
SPF allows any server to send (+all)
The record ends in +all, or in all with no sign, which means the same. Every server on the internet passes SPF for your domain. Someone forging your domain as the bounce address passes too, and that pass counts toward DMARC. SignalDNS marks this as a problem.
How to fix it: list the services that send your mail and end with ~all or -all, as in v=spf1 include:_spf.google.com ~all.
SPF doesn’t say what to do with other senders
The record ends in ?all (neutral), or has no all at all, which RFC 7208 treats the same way. It lists your servers but says nothing about the rest. SignalDNS marks this as needing attention. There are two useful endings:
~all(softfail) says mail from other servers is probably not yours. RFC 7208 asks receivers not to reject on this alone, but they may look at it more closely. Your DMARC policy decides the rest.-all(fail) says mail from other servers isn’t allowed. Receivers may reject it. RFC 9989 warns that some receivers check SPF before DMARC, so-allcan block a message that DKIM would have passed, such as a forwarded one.
How to fix it: end the record with ~all, or -all if you’re sure it lists every service that sends your mail and you accept the risk above. Some providers’ guides use ?all; change it the same way.
SPF doesn’t include your email provider
Your main MX record (the one with the lowest number) points at a mailbox provider we recognise, but SPF doesn’t include that provider. Mailbox providers usually send your outgoing mail as well, so mail you send through them may fail SPF. SignalDNS marks this as needing attention.
How to fix it: add the provider’s include before the all term, such as v=spf1 include:spf.protection.outlook.com -all:
- Google Workspace:
include:_spf.google.com - Microsoft 365:
include:spf.protection.outlook.com - Zoho Mail:
include:zohomail.com(we accept any Zoho include) - Proton Mail:
include:_spf.protonmail.ch - Fastmail:
include:spf.messagingengine.com - iCloud Mail:
include:icloud.com - GoDaddy:
include:secureserver.net
If the provider only receives your mail and something else sends it, you don’t need its include. We don’t expect filtering gateways, such as Mimecast and Proofpoint, in SPF: receiving your mail doesn’t mean they send it. If you do send through one, add the include its documentation gives.
Part of SPF couldn’t be checked
The lookup for an include or redirect failed: it timed out, or a name server returned an error such as SERVFAIL. That says nothing about whether the record is right, so we report that part as not checked. Lookups inside it aren’t counted, so the real total may be higher.
Receivers that hit the same failure get a temporary error (temperror), and may hold the message and try again later.
How to fix it: check again in a few minutes. If the same include keeps failing, that domain’s name servers have a problem. If it’s yours, see name servers; if it’s a provider’s, let them know.
Includes that use macros
SPF macros, written with %, such as include:%{i}._spf.example.net, build a name from details of each message, such as the sending server’s address. Those details aren’t known in advance, so we don’t follow an include or redirect that uses one. It counts as one lookup, but the lookups inside it can’t be counted, so the real total may be higher.
Macros are valid under RFC 7208, and we don’t flag them as a mistake.
Your provider’s guides
- Google Workspace: set up SPF
- Microsoft 365: set up SPF
- Zoho Mail: SPF
- Proton Mail: anti-spoofing for custom domains (SPF, DKIM, and DMARC)
- Fastmail: manual DNS configuration
- iCloud Mail: set up an existing domain
- GoDaddy: add an SPF record
- Namecheap: add TXT, SPF, DKIM, and DMARC records
What we can’t tell from outside
We read the published records. We don’t send mail, so we can’t see which servers actually send yours, or whether a message passes; DMARC reports show that. We don’t expand macros, look up the addresses behind a and mx terms, or count void lookups (names that return nothing), which RFC 7208 suggests receivers limit to two. A record we mark OK can still be missing a service you use.
Sources
- RFC 7208: Sender Policy Framework (SPF) for Authorizing Use of Domains in Email, Version 1, section 4.6.4 for the lookup limit
- RFC 9989: Domain-Based Message Authentication, Reporting, and Conformance (DMARC), section 7.1 for
-all
Last reviewed .