Email authentication

SPF record explained: syntax, examples and setup

An SPF record is one line of DNS text that lists the servers allowed to send email for your domain. This guide covers its syntax, ready-to-use examples, the 10-lookup limit and the errors that make SPF fail.

Updated October 9, 2026 · 10 min read

SPF record v=spf1 ip4:192.0.2.10 include:_spf.google.com ~all explained term by term, with a pass and a softfail result

An SPF record is a TXT record in your domain’s DNS that lists every server allowed to send email for the domain. Receiving mail servers look it up for each incoming message and compare the sending server’s IP address with the list. The format is defined in RFC 7208, and a typical record is one short line:

example.com.  TXT  "v=spf1 include:_spf.google.com ~all"

That record says: servers listed in Google’s SPF record may send for example.com; mail from anywhere else is suspicious.

What an SPF record does

SPF (Sender Policy Framework) answers one question for the receiving server: is this IP address allowed to send mail for this domain?

The domain it checks is not the one in the visible From line. SPF checks the envelope sender, the address in the SMTP MAIL FROM command that ends up in the Return-Path header, and RFC 7208 recommends checking the HELO name too (section 2.3). When an email service sends with its own bounce domain, SPF is checked against that domain, not yours. Linking SPF to the From address people see is the job of DMARC, covered in what is a DMARC record.

The check returns one of seven results (section 2.6):

ResultMeaning
passThe IP address is authorized.
failThe domain says the IP address is not authorized (usually because -all matched).
softfailThe IP address is probably not authorized (usually because ~all matched).
neutralThe domain makes no statement about this IP address (usually because ?all matched).
noneThe domain has no SPF record.
temperrorA temporary DNS error during the check. Receivers may retry later.
permerrorThe record could not be interpreted: a syntax error, two records, or too many DNS lookups.

SPF records must be published as TXT records. The separate SPF record type was dropped in RFC 7208 (section 3.1), so don’t create one even if your DNS host still offers it.

SPF record syntax: mechanisms and qualifiers

Every SPF record has the same structure: the version tag, then a list of terms separated by spaces, usually ending with all.

v=spf1 ip4:192.0.2.10 include:_spf.google.com include:mail.zendesk.com -all

The receiver checks the mechanisms from left to right and stops at the first one that matches the sending IP address. The qualifier in front of that mechanism decides the result.

Mechanisms and modifiers

TermExampleMatches when the sending IP …DNS lookups
ip4ip4:192.0.2.0/24is in this IPv4 address or range0
ip6ip6:2001:db8::/32is in this IPv6 address or range0
aa or a:mail.example.comis an A or AAAA address of the domain (the current domain if none is given)1
mxmx or mx:example.comis an address of one of the domain’s MX hosts1
includeinclude:_spf.google.compasses the SPF record of the other domain1, plus the lookups inside that record
existsexists:%{i}.spf.example.commakes the (expanded) name resolve to any A record1
ptrptrhas reverse DNS in the domain. RFC 7208 says it SHOULD NOT be published.1
all-allalways matches. It goes last.0
redirect= (modifier)redirect=_spf.example.comuse that domain’s record when nothing else matched1
exp= (modifier)exp=explain.example.comnot a match: points to an explanation text for rejections0

a and mx accept a prefix length, so a:mail.example.com/28 authorizes the whole /28 network around that host. Section 5 of the RFC defines every mechanism in detail.

redirect= is useful when many domains share one policy. Each domain publishes v=spf1 redirect=_spf.example.com, and you maintain the list in one place. The modifier is ignored when the record also contains an all mechanism (section 6.1), so a redirect record never ends with ~all or -all.

Qualifiers

QualifierExampleResult when it matches
+ (default)+mx, or just mxpass
--allfail
~~allsoftfail
??allneutral

The + is implied when no qualifier is written, which is why include:_spf.google.com means “pass if Google’s list matches”.

Long records

A single string in a TXT record holds at most 255 characters. Longer SPF records are published as several strings in one record; receivers join them without adding spaces (section 3.3), so end each string with a space:

example.com.  TXT  ( "v=spf1 ip4:192.0.2.0/24 ip4:198.51.100.0/24 ip4:203.0.113.0/24 "
                     "include:_spf.google.com ~all" )

Some DNS hosts’ web forms split long values for you, others expect the quoted strings; their help pages say which. RFC 7208 also asks that the record stay small enough for the DNS answer to fit in 512 bytes (section 3.4).

SPF record examples: Google Workspace, Microsoft 365, multiple senders

The include values below come from each provider’s own documentation, checked October 9, 2026.

Google Workspace SPF record

Google’s SPF setup page gives this record for domains that send only through Google Workspace, and recommends ~all:

example.com.  TXT  "v=spf1 include:_spf.google.com ~all"

To add another sender, put its include: before ~all in the same record. Google notes that SPF can take up to 48 hours to start working after you publish it.

Microsoft 365 SPF record

Microsoft’s SPF configuration guide gives this record for Microsoft 365 domains and recommends -all, because it also recommends DKIM and DMARC for the domain:

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

GCC High and DoD tenants use include:spf.protection.office365.us instead. Your *.onmicrosoft.com domain already has an SPF record that you can’t change.

Multiple senders

A domain on Microsoft 365 that also sends from its own server and from Zendesk lists all three:

example.com.  TXT  "v=spf1 ip4:198.51.100.25 include:spf.protection.outlook.com include:mail.zendesk.com -all"

Microsoft recommends a subdomain for bulk email services and other senders that aren’t under your direct control. The subdomain gets its own record, because the record on the main domain doesn’t cover it:

mg.example.com.  TXT  "v=spf1 include:mailgun.org ~all"

A domain that sends no email at all publishes a record that authorizes nobody:

example.com.  TXT  "v=spf1 -all"

SPF includes for common services

ServiceSPF includeNoteProvider docs
Google Workspaceinclude:_spf.google.comGoogle recommends ~all.Docs
Microsoft 365include:spf.protection.outlook.comMicrosoft recommends -all. GCC High and DoD use spf.protection.office365.us.Docs
Zoho Mailinclude:zohomail.comZoho suggests one.zoho.com instead if you send from several Zoho apps.Docs
Proton Mailinclude:_spf.protonmail.chDocs
Fastmailinclude:spf.messagingengine.comFastmail's own example ends with ?all.Docs
iCloud+ (custom domain)include:icloud.comDocs
Hostinger Emailinclude:_spf.mail.hostinger.comDocs
IONOSinclude:_spf-eu.ionos.comOnly needed when your DNS is not at IONOS: IONOS publishes its SPF rule by default for domains whose DNS it hosts.Docs
ALL-INKL.COMinclude:spf.kasserver.comALL-INKL's own example is v=spf1 a mx include:spf.kasserver.com ~all.Docs
SendGridinclude:sendgrid.netNot needed if you set up Domain Authentication with automated security (CNAME records).Docs
Mailguninclude:mailgun.orgMailgun asks for it on the domain you verified with them, often a subdomain.Docs
Mailjetinclude:spf.mailjet.comDocs
Zendeskinclude:mail.zendesk.comZendesk's own example ends with -all.Docs
Freshdeskinclude:email.freshdesk.comDocs
CleverReachinclude:spf.crsend.comCleverReach's own example for a new record is v=spf1 a mx include:spf.crsend.com ~all.Docs

Values checked against each provider's documentation on October 9, 2026. Providers change their setup now and then, so follow their current instructions if they differ.

The 10-lookup limit and flattening

Section 4.6.4 caps the DNS lookups for one SPF check at 10. include, a, mx, ptr, exists and redirect count, and so does every one of those terms inside the records you include. ip4, ip6, all and exp don’t. A check that needs an 11th lookup ends with permerror.

Here is how a record adds up (the included domains are fictional):

TermLookups
ip4:192.0.2.100
mx1
include:_spf.mailhost.example, whose record contains 2 more includes (with only ip4 inside)3
include:spf.crm.example, whose record contains 1 a and 1 more include (with only ip4 inside)3
~all0
Total7

Two more limits apply. Lookups that return no data or a “domain doesn’t exist” answer (“void lookups”) should be limited to two, and exceeding that limit also produces permerror. And an include that points to a domain without an SPF record returns permerror too (section 5.2), which is what happens after a typo in an include value.

The count depends on the providers’ current records, which they change without notice. The SPF checker resolves the whole include tree and shows the live total.

How to get back under 10

  1. Remove senders you no longer use. Old CRMs and newsletter tools are the usual leftovers.
  2. Check whether a sender needs the include at all. Many services send with their own bounce domain, so SPF is checked on their domain, and they authenticate your domain with DKIM instead. Their setup guide says which.
  3. Move bulk senders to a subdomain with its own SPF record, as in the Mailgun example above.
  4. Replace includes with IP ranges (“flattening”). This saves lookups, but your record goes stale as soon as the provider changes its servers. Microsoft suggests replacing an include with ip4: or ip6: values when a vendor has “a stable, documented set of sending IP addresses”; for everyone else, keep the include.

~all vs -all

The qualifier on all decides what the record says about every server you didn’t list:

Once DMARC is in place, the difference matters less than it seems: DMARC counts both ~all and -all as SPF failures, as Microsoft’s guide points out, and the DMARC policy decides what happens to the message. Microsoft adds one exception: its filtering effectively ignores the DMARC policy for ~all failures in messages without a DKIM signature, which is why it recommends -all. Use -all when you are sure every legitimate sender is listed, and ~all while you are still finding them.

Common SPF errors (PermError, multiple records)

ProblemResultFix
Two TXT records starting with v=spf1permerror (section 3.2)Merge them into one record.
More than 10 DNS lookupspermerrorRemove, move or flatten includes (see above).
include: of a domain without an SPF record, often a typopermerrorCopy the value from the provider’s documentation.
Syntax error, for example include: _spf.google.com (space after the colon) or ip4:192.0.2.0/33permerrorRebuild the record with the SPF record generator.
DNS timeout or server failure during the checktemperror (section 4.4)Usually transient; check your DNS host if it persists.
Record published as type SPF instead of TXTnonePublish it as TXT.
Sending subdomain without its own recordnoneAdd a record on the subdomain.
A sender’s IP address is missingsoftfail or failAdd its include or IP range.

The double record usually appears when a new service’s setup guide says “add this SPF record” and someone adds a second one instead of editing the first. Merge them like this:

; Before: two records, SPF returns permerror for every message
example.com.  TXT  "v=spf1 include:_spf.google.com ~all"
example.com.  TXT  "v=spf1 include:mail.zendesk.com -all"

; After: one record with both senders and one all
example.com.  TXT  "v=spf1 include:_spf.google.com include:mail.zendesk.com ~all"

Other TXT records on the domain, such as site verification codes, are unaffected. Only records starting with v=spf1 count.

A permerror is easy to miss because much of your mail still arrives, signed with DKIM. It shows up as spf=permerror in the Authentication-Results header of delivered messages, which the email header analyzer reads for you, and, once your DMARC policy is reject, as bounces such as 550 5.7.26 for mail that had no DKIM signature to fall back on.

Create and check your SPF record

  1. List every service that sends email as your domain: your mailbox provider, newsletter tool, CRM, help desk, invoicing system and your own servers.
  2. Build the record with the SPF record generator. It has presets for the services above and counts the lookups before you publish.
  3. Publish it as one TXT record on the domain itself (@ at most DNS hosts). If a v=spf1 record exists, edit it instead of adding a second one.
  4. Check what receivers see. Enter your domain below; the checker shows the record, every include and the lookup count.

Live DNS lookup over DNS-over-HTTPS. You can also paste an email address.

SPF is one of three records. Add DKIM signing, explained in what is a DKIM record, and a DMARC policy from the DMARC generator. Gmail and Yahoo require all three from bulk senders; the Gmail and Yahoo sender requirements list the rest.

Frequently asked questions

What is an SPF record?

A TXT record on your domain that starts with v=spf1 and lists the servers allowed to send email for it, for example v=spf1 include:_spf.google.com ~all. Receiving servers compare the IP address of the sending server with that list (RFC 7208).

What should my SPF record be for Google Workspace?

If only Google Workspace sends mail for your domain, Google's documentation gives v=spf1 include:_spf.google.com ~all. If other services send as your domain too, add their include values before ~all, in the same record.

How many SPF records can a domain have?

One. If a domain publishes two TXT records that start with v=spf1, the SPF check ends with a permanent error (permerror) and fails for all of its mail. Merge them into one record with one v=spf1 at the start and one all at the end.

Do subdomains need their own SPF record?

Yes, if they send email. SPF is checked for the exact domain in the envelope sender, so the record on example.com doesn't cover news.example.com. Publish a separate record on each sending subdomain.

What does ~all mean in an SPF record?

Softfail: servers that are not listed are probably not allowed to send for the domain, and receivers should accept such mail but treat it as suspicious. -all (fail) is the stronger statement. Google recommends ~all for Google Workspace, Microsoft recommends -all for Microsoft 365.

Email validation API

Validate emails in your app

emailvalidation.io checks syntax, MX records and the mailbox over SMTP, flags disposable, role and free addresses and returns a quality score, in one request.

/v1/info Email validation API Read the documentation

100 free validations every month. No credit card required.

GET https://api.emailvalidation.io/v1/info?email=support@emailvalidation.io

{
  "email": "support@emailvalidation.io",
  "user": "support",
  "tag": "",
  "domain": "emailvalidation.io",
  "format_valid": true,
  "mx_found": true,
  "smtp_check": true,
  "catch_all": null,
  "role": true,
  "disposable": false,
  "free": false,
  "score": 0.64,
  "state": "deliverable",
  "reason": "valid_mailbox",
  "did_you_mean": ""
}

Keep reading

Start using our email validation software today!

Get 100 validations per month for free