What is SPF? SPF records explained

SPF lists the servers allowed to send mail for your domain. Learn SPF record syntax, include, ip4, ~all vs -all, the 10-lookup limit and common mistakes.

Updated September 30, 2026

SPF (Sender Policy Framework, RFC 7208) is a TXT record on your domain that lists the servers allowed to send mail using that domain in the envelope sender (the Return-Path). It starts with v=spf1, lists senders with mechanisms like ip4: and include:, and ends with -all or ~all for everything else. A domain can have only one SPF record, and checking it may take no more than 10 DNS lookups.

How SPF works

Every email has two sender addresses. The one people see is the header From. The other is the envelope sender, given in the SMTP MAIL FROM command, which is where bounces go and which shows up in the delivered message as Return-Path. SPF checks the second one.

When a server receives mail with MAIL FROM:<bounce@example.com>, it looks up the TXT record for example.com, finds the one starting with v=spf1, and checks whether the connecting IP address is listed. The result is pass, fail, softfail, neutral, none, temperror or permerror.

SPF record syntax: mechanisms

A record is v=spf1 followed by terms separated by spaces. Receivers read the mechanisms left to right and stop at the first one that matches the sending IP.

MechanismMatches whenDNS lookup?
ip4:192.0.2.10The sender’s IPv4 address matches (a CIDR range like 192.0.2.0/24 works too).No
ip6:2001:db8::/32The sender’s IPv6 address is in the range.No
aThe IP is one of the domain’s A or AAAA records. a:host.example.com checks another name.Yes
mxThe IP belongs to one of the domain’s MX hosts.Yes
include:_spf.example.netThe other domain’s SPF record returns pass for this IP. This is how you authorize an email provider.Yes, plus everything inside it
exists:%{i}._spf.example.comThe constructed name has an A record. Used with macros for dynamic SPF.Yes
ptrReverse DNS of the IP points to the domain. Deprecated: RFC 7208 says not to use it.Yes
allAlways matches. Put it last as the catch-all.No

Qualifiers: + - ~ ?

Each mechanism can have a prefix that sets the result when it matches. With no prefix, the result is pass.

QualifierResultTypical use
+passThe default, so +include: and include: are the same.
-fail-all: nothing else may send.
~softfail~all: others probably aren’t allowed; accept but treat with suspicion.
?neutral?all: no statement. Rarely useful.

If nothing matches and there’s no all or redirect, the result is neutral, as if the record ended in ?all.

Modifiers: redirect and exp

  • redirect=_spf.example.com replaces your record with another domain’s record when nothing else matched. It’s how several domains share one policy, and how hosted SPF works. It costs one DNS lookup, and it’s ignored if the record contains all anywhere.
  • exp=explain.example.com points to a TXT record with a message to show senders whose mail failed. It’s evaluated only after a fail and doesn’t count toward the lookup limit. Few receivers display it.

A worked SPF example

A company sends from Google Workspace, one office mail server and a marketing platform:

HostTypeValue
@TXT
v=spf1 ip4:203.0.113.25 include:_spf.google.com include:<include from your marketing platform> ~all
Use the exact include value each provider documents. Your own IPs go in ip4 or ip6.
  • ip4:203.0.113.25 authorizes the office server directly, with no DNS lookup.
  • include:_spf.google.com authorizes Google Workspace’s servers, as Google documents.
  • The second include authorizes the marketing platform, if it uses your domain as its envelope sender.
  • ~all soft-fails everything else.

The SPF record generator builds a record like this from a list of senders, and the SPF checker shows how many lookups yours uses.

Only one SPF record per domain

A domain must publish exactly one TXT record starting with v=spf1. Two records produce a permerror, which is treated as an SPF failure for DMARC. This usually happens when a new provider’s setup instructions say “add this SPF record” and someone adds a second one. Merge them instead: one v=spf1, all the mechanisms, one all at the end.

A single TXT string can hold at most 255 characters. Longer records are split into several quoted strings in the same record, which receivers join without spaces. Most DNS dashboards do this for you.

The 10 DNS-lookup limit and the 2 void-lookup limit

Checking SPF may cause at most 10 DNS lookups from include, a, mx, ptr, exists and redirect, counting everything inside nested includes. Go over and the result is permerror, so your mail fails SPF everywhere. Separately, receivers should stop after 2 “void” lookups, ones that return no records or a nonexistent domain, which catches includes left pointing at retired services. ip4, ip6 and all are free. Most growing companies hit the 10-lookup limit eventually; fixing “too many DNS lookups” shows how to get back under it.

Check your SPF record

See your SPF record, its lookup count and whether it passes, alongside DMARC and DKIM.

Why SPF alone often doesn’t satisfy DMARC

DMARC only counts an SPF pass if the envelope sender’s domain aligns with the header From domain. Many email platforms use their own bounce domain by default, so a newsletter shows From: news@example.com but has a Return-Path like bounces+123@mail.esp.example. SPF passes, for the platform’s domain, and DMARC ignores that pass.

That’s also why adding a provider’s include to your record doesn’t always help: SPF never checks your record for that mail. The fix is DKIM signing with your own domain, plus a custom return-path (often called a bounce or envelope domain) on a subdomain like bounce.example.com if the provider offers one. DMARC alignment explained has examples.

~all or -all under DMARC?

For DMARC both are simply “not a pass”, so the choice doesn’t change DMARC results. The difference is what receivers do with SPF on its own. Some reject -all failures during the SMTP conversation, before DMARC is evaluated, which can bounce a forwarded message that would have passed DMARC through DKIM. For that reason many operators use ~all once DMARC is enforcing and let the DMARC policy do the blocking. Use -all on domains that send no mail at all.

Subdomains need their own SPF record

SPF doesn’t inherit. A record on example.com says nothing about mail.example.com: if a service uses mail.example.com as its envelope sender, that name needs its own v=spf1 record. This is also a feature, since you can give a bulk-mail subdomain its own record and keep its includes out of your main one.

Forwarding breaks SPF

When a message is forwarded (a university alias to Gmail, say), the forwarding server sends it from its own IP, which isn’t in your SPF record, so SPF fails at the final destination. Some forwarders rewrite the envelope sender (SRS) so SPF passes for their own domain, but that domain doesn’t align with yours either. DKIM usually survives forwarding, which is why you should never rely on SPF alone.

Frequently asked questions

Where do I add an SPF record?

At your DNS host, as a TXT record on the domain itself (host @ or blank at most providers). The SPF record type (type 99) is obsolete; use TXT.

Does SPF check the From address?

No. SPF checks the envelope sender (MAIL FROM, shown as Return-Path) and, separately, the HELO name. DMARC is what connects SPF to the visible From address.

Should I include mx or a in my SPF record?

Only if those hosts actually send mail. With Google Workspace or Microsoft 365, your MX hosts receive mail but outbound mail is covered by the provider’s include, so mx just wastes a lookup.

How many includes can an SPF record have?

There’s no separate include limit. The limit is 10 DNS lookups in total, and each include costs at least one plus whatever its own record uses.

What does SPF softfail mean?

The sending IP matched ~all: the domain says it probably isn’t authorized but asks receivers not to reject on SPF alone. For DMARC, softfail is the same as fail.