Guides · Email · Updated

SPF record syntax: mechanisms, qualifiers and examples

An SPF record is a single TXT record that starts with v=spf1, lists the sources allowed to send mail for the domain, and ends with a rule for everything else, usually ~all or -all.

Anatomy of a record

v=spf1 ip4:203.0.113.0/24 include:_spf.google.com mx -all
  • v=spf1: the version. Must come first, exactly like this.
  • ip4:203.0.113.0/24: allow this range.
  • include:_spf.google.com: also allow whatever Google's SPF record allows.
  • mx: allow the servers in this domain's MX records.
  • -all: fail everything else.

Receivers read the terms left to right and stop at the first match.

Validate a domain's SPF record and count its lookups:

Mechanisms

MechanismMatches whenDNS lookup?
ip4:The sender's IPv4 address is in the address or rangeNo
ip6:The sender's IPv6 address is in the address or rangeNo
aThe sender is one of the domain's A or AAAA addressesYes
mxThe sender is one of the domain's MX hostsYes
include:The other domain's SPF record passesYes
exists:The given name has an A record (used for advanced macros)Yes
ptrReverse DNS matches. Deprecated; don't useYes
allAlways. Goes lastNo

Two modifiers can appear too: redirect=otherdomain uses another domain's record instead of this one (only when there is no all), and exp= points to an explanation text for failures.

Qualifiers

Each mechanism can carry a prefix that decides the result when it matches. Without one, it means +.

QualifierResultTypical use
+PassDefault; never write +all
-Fail-all: strict, once every sender is listed
~Softfail~all: suspicious but accept, while you are still checking
?NeutralNo opinion; rarely useful

The 10-lookup limit

Checking an SPF record may trigger at most 10 DNS lookups (RFC 7208, section 4.6.4), counting include, a, mx, exists, ptr and redirect, including those inside included records. Go over and SPF returns a permanent error, which receivers treat as a failure. ip4, ip6 and all don't count.

Each large provider's include often uses several lookups on its own, so a domain with five or six services can hit the limit quickly. To get back under it:

  • Remove services you no longer use.
  • Drop a and mx if those servers don't send mail.
  • Move a service that sends a lot to a subdomain (for example news.example.com) with its own SPF record.
  • Replace an include with the provider's published ip4: ranges only if the provider says they are stable.

Rules that trip people up

  • One record only. Two TXT records starting with v=spf1 is a permanent error. Merge them.
  • Long records are split into strings. A TXT string holds 255 characters; longer records are written as several quoted strings that receivers join without spaces: "v=spf1 include:a.example " "include:b.example -all".
  • Put it on the domain that sends. The record belongs at the domain in the return-path address, which is usually your domain but can be a subdomain your provider sets up.
  • Domains that never send mail should say so: v=spf1 -all.
  • SPF alone doesn't protect the From address. Pair it with DKIM and DMARC; see SPF, DKIM and DMARC explained.

Examples

Google Workspace only

v=spf1 include:_spf.google.com ~all

Microsoft 365 only

v=spf1 include:spf.protection.outlook.com -all

Your own server plus a mailbox provider

v=spf1 ip4:203.0.113.25 include:_spf.google.com -all

A domain that sends no mail

v=spf1 -all

Always copy a provider's include from its own documentation. A mistyped include silently stops matching, and mail from that service starts failing.

After you publish

DNS changes take time to reach every resolver; see what is DNS for why. Then run the SPF checker to confirm the record parses, stays under 10 lookups and has no duplicates, and set up DMARC so you hear about failures.

Frequently asked questions

Can a domain have more than one SPF record?

No. Two TXT records starting with v=spf1 make SPF fail with a permanent error. Merge them into one record with several include: mechanisms.

Should I use ~all or -all?

-all (fail) is stricter and fine once you are sure every sender is listed. ~all (softfail) is safer while you are still finding senders. With DMARC in place, receivers treat both as an SPF failure.

What happens if I go over 10 DNS lookups?

SPF returns a permanent error and receivers treat the message as failing SPF. Remove unused includes, or replace an include with the provider's ip4: ranges if it publishes stable ones.