The short answer: An SPF record is a single DNS TXT record that starts with v=spf1, followed by space-separated terms: mechanisms (ip4, ip6, a, mx, include, exists, all) that name authorized senders, optional qualifiers (+, -, ~, ?) that set the result, and optional modifiers (redirect, exp). Terms are evaluated left to right and the first match wins. The rules come from RFC 7208.
This page is a reference. If you only want a working record, the SPF generator builds one and the SPF checker validates it.
The Anatomy of an SPF Record
v=spf1 ip4:203.0.113.0/24 include:_spf.google.com include:servers.mcsv.net ~all
| Part | Role |
|---|---|
v=spf1 |
Version tag. Must be the first term. |
ip4:203.0.113.0/24 |
Mechanism: authorizes an IP range. |
include:_spf.google.com |
Mechanism: authorizes whatever that domain's SPF record authorizes. |
~all |
Mechanism with a qualifier: what to do with everything else. |
Syntax rules that trip people up:
- The record lives in a TXT record at the domain being checked (the root domain, or a subdomain if you send from one). It is not a separate "SPF" record type; that type was retired in RFC 7208.
- Terms are separated by one or more spaces. Mechanism names and the
v=spf1tag are case-insensitive. - You may publish only one SPF record per domain name. Two records that begin with
v=spf1produce apermerror, and receivers treat that as a failure.
The Problem SPF Solves
Email was designed without any check on who is sending. SMTP lets a server claim to be sending from any address. Nothing in the original protocol stops a stranger from sending a message that says it comes from accounts@yourcompany.com.
SPF adds one verification: the domain owner publishes the list of servers that may send for it, and receivers check connecting servers against that list. A forged message sent from a server that is not on the list fails the check.
SPF does not encrypt anything, does not stop the content of a message from being malicious, and does not by itself decide what happens to a failure. It supplies a result that the receiver, and your DMARC policy, act upon.
Envelope sender versus the visible From address
This is the point that confuses almost everyone. A message has two sender identities:
| Identity | Also called | Where it lives | Who sees it |
|---|---|---|---|
MAIL FROM |
Envelope sender, Return-Path, bounce address | The SMTP conversation; saved as the Return-Path header |
Mostly invisible to recipients |
From: |
Header From, visible From | The message headers | Shown in the mail client |
SPF validates the first one only. A spammer can pass SPF using their own domain in MAIL FROM while the visible From: shows your brand. SPF alone never notices.
That is why DMARC exists. DMARC requires that the domain SPF authenticated (or the domain in a valid DKIM signature) matches the visible From: domain. This match is called alignment. Without it, a pass does not count for DMARC. The details are in SPF, DKIM and DMARC explained.
This also explains a common surprise: when you send through a marketing platform, MAIL FROM is often the platform's own bounce domain. SPF passes for the platform's domain, not yours, so it is unaligned for DMARC purposes, and DKIM must carry the DMARC pass instead.
How SPF Fits With DKIM and DMARC
The three standards check different things:
| Standard | Question it answers | What it checks |
|---|---|---|
| SPF | Is this server allowed to send for the envelope domain? | Sending IP against DNS list |
| DKIM | Was this message altered, and did the signing domain authorize it? | Cryptographic signature in a header |
| DMARC | Does an authenticated domain match the visible From, and what should happen if not? | Alignment of SPF or DKIM, plus your policy |
A sound setup uses all three. SPF covers the simple case of servers you control; DKIM survives forwarding; DMARC ties both to the From address people see and tells receivers to quarantine or reject failures. Start with a monitoring policy if you are new to this, as explained in DMARC policy: none, quarantine, reject.
Typical Records for Common Setups
| Setup | Example record |
|---|---|
| Google Workspace only | v=spf1 include:_spf.google.com ~all |
| Microsoft 365 only | v=spf1 include:spf.protection.outlook.com ~all |
| Microsoft 365 plus a marketing tool | v=spf1 include:spf.protection.outlook.com include:servers.mcsv.net ~all |
| Domain that never sends email | v=spf1 -all |
Always take the exact include value from your provider's current documentation, since vendors occasionally change them. The adding third-party senders guide walks through that process.
Domains that never send mail deserve the last record in the table. Without it, attackers can spoof parked domains and lookalike subdomains freely.
Common Beginner Mistakes
- Publishing a second record when adding a new tool, instead of editing the existing one.
- Forgetting a sender, such as an invoicing system or website contact form, so its mail fails SPF.
- Leaving old vendors in the record, which wastes lookups and authorizes services you no longer use.
- Assuming SPF is the whole job. Passing SPF with a vendor's bounce domain does nothing for DMARC alignment.
- Never checking again. Records drift as teams add tools. Re-test after every change, and see the email deliverability checklist for a regular routine.
Gmail and Yahoo now expect SPF and DKIM from anyone sending in volume; the specifics are in Google and Yahoo bulk sender requirements.
How to Set Up and Check Yours
- List every service that sends email as your domain: your mailbox provider, marketing tools, billing system, helpdesk, website forms.
- Build a single record with the SPF generator.
- Publish it as one TXT record at your domain's root.
- Test it with the SPF checker, which shows lookup counts and any errors.
- Send a test email and confirm
spf=passin the headers. - Add DKIM and DMARC. The email security score shows what is missing.
The Version Tag
v=spf1 is the only valid version. It must appear at the very start of the TXT value, with no leading characters. A record such as " v=spf1 ..." with a stray leading space, or spf1 ... with the v= missing, is not recognized as SPF and the domain evaluates to none.
Qualifiers
A qualifier is a single character placed directly in front of a mechanism. It decides what result is returned if that mechanism matches.
| Qualifier | Name | Result on match | Typical use |
|---|---|---|---|
+ |
Pass | pass |
Default when no qualifier is written |
- |
Fail | fail (hard fail) |
-all to reject unlisted senders |
~ |
SoftFail | softfail |
~all during rollout or as a long-term setting |
? |
Neutral | neutral |
?all, effectively "no opinion" |
include:example.net and +include:example.net mean the same thing. For help choosing between -all and ~all, see SPF hard fail vs soft fail.
Mechanisms
A mechanism describes a set of hosts. If the sending IP is in that set, the mechanism matches.
ip4 and ip6
ip4:192.0.2.10
ip4:198.51.100.0/24
ip6:2001:db8:1234::/48
These compare the connecting IP address directly. They need no DNS lookup and cost nothing against the lookup limit. An ip4 address with no prefix means /32 (one host). ip6 without a prefix means /128.
a
a
a:mail.example.com
a:mail.example.com/24
a/24//64
Matches if the sending IP equals an A (or AAAA) record of the named domain. With no domain, it uses the domain being checked. The first CIDR is the IPv4 prefix and the second, after //, is the IPv6 prefix. Costs one DNS lookup.
mx
mx
mx:example.org
Matches if the sending IP is an address of one of the domain's MX hosts. Useful only when your inbound servers also send your mail. It costs one lookup for the MX query, plus one for each MX hostname resolved (up to 10 names; more than that is a permerror).
include
include:_spf.google.com
Evaluates another domain's SPF record. If that record returns pass, the include matches and the qualifier applies. If the inner result is anything else (fail, softfail, neutral), the include simply does not match and evaluation continues with the next term. An inner -all does not fail your mail. If the included domain has no SPF record at all, the result is permerror. Each include is one lookup, plus all lookups inside the included record. See adding third-party senders to SPF for the vendor-by-vendor details.
exists
exists:%{i}._spf.example.com
Matches if the named domain resolves to any A record (the value is ignored). Almost always combined with macros to build per-IP lookups.
ptr
ptr:example.com
Performs a reverse lookup on the sending IP and checks the resulting names. RFC 7208 says senders should not use it: it is slow, unreliable and loads the receiver's DNS. Do not publish it.
all
-all
~all
?all
+all
Always matches. It goes last, because anything written after all is never evaluated. Never publish +all: it authorizes every server on the internet to send as you.
Modifiers
Modifiers are written name=value and, unlike mechanisms, have no qualifier. Each may appear at most once.
redirect
v=spf1 redirect=_spf.example.com
Replaces the current record with the policy of another domain. It is evaluated only after every mechanism in the record has failed to match, and it is ignored if the record contains an all mechanism. If the target has no SPF record, the result is permerror.
redirect vs include: use include to add another party's senders to your own list. Use redirect when a whole domain should share one policy, for example many parked or secondary domains all pointing to one master record. The key behavior difference is that redirect adopts the target's final result, including its -all, while include only contributes matches.
exp
v=spf1 mx -all exp=explain._spf.example.com
Names a TXT record whose text is returned in the SMTP rejection message when the result is fail. Most domains skip it.
Unknown modifiers
Unknown modifier names are ignored. An unknown mechanism is a permerror.
Evaluation Order and Results
Receivers evaluate left to right and stop at the first match. The qualifier on that mechanism becomes the result. If nothing matches and there is no redirect, the result is neutral.
For a message sent from 198.51.100.7 against this record:
v=spf1 ip4:203.0.113.0/24 include:_spf.google.com -all
ip4:203.0.113.0/24does not contain the IP, so move on.include:_spf.google.comis evaluated; Google's ranges do not include it, so no match.-allmatches everything, so the result isfail.
The possible results are pass, fail, softfail, neutral, none (no SPF record), temperror (a transient DNS problem) and permerror (the record is broken or over a limit).
Put all last. Lookup limits apply to what is actually evaluated.
Macros
Macros let one record adapt to the message being checked. They start with %{ and end with }.
| Macro | Expands to |
|---|---|
%{i} |
Sending IP address |
%{s} |
Sender (MAIL FROM) address |
%{l} |
Local part of the sender |
%{o} |
Domain of the sender |
%{d} |
Domain currently being checked |
For example, exists:%{i}._spf.example.com turns a connection from 192.0.2.5 into a lookup for 5.2.0.192._spf.example.com. Macros appear mainly in exists and exp; most small domains never need them.
Length Limits
255 characters per string
A DNS TXT record is made of one or more character-strings, and each is limited to 255 bytes. A long SPF record must be split into several quoted strings inside the same TXT record:
example.com. IN TXT "v=spf1 ip4:203.0.113.0/24 ip4:203.0.114.0/24 ip4:203.0.115.0/24 " "include:_spf.google.com include:servers.mcsv.net -all"
Receivers join the strings with no added space, so end the first string with a trailing space (or begin the next with one). Many DNS panels split automatically; if yours has one text box, paste the whole value and let it do so. Splitting into separate TXT records is wrong, because that creates two SPF records.
512 bytes for UDP
Classic DNS responses over UDP were limited to 512 bytes. Larger answers need EDNS0 or a retry over TCP, which most resolvers now handle, but RFC 7208 still advises keeping the whole TXT answer within that size. Longer records risk being dropped by restrictive networks, so aim for roughly 450 characters at most.
10 DNS lookups and 2 void lookups
The count covers include, a, mx, ptr, exists and redirect. More than 10 returns permerror. More than two lookups returning no data (NXDOMAIN or empty answers) also produce permerror. The full treatment is in SPF too many DNS lookups.
Annotated Examples
Google Workspace only:
v=spf1 include:_spf.google.com ~all
One include (Google's record adds its own lookups), soft fail for everyone else.
Microsoft 365 plus a marketing platform plus an office IP:
v=spf1 ip4:203.0.113.25 include:spf.protection.outlook.com include:servers.mcsv.net -all
The IP costs nothing, each include costs at least one lookup, and -all rejects any unlisted source.
A domain that does not send mail:
v=spf1 -all
Publish this on parked domains so spoofed mail fails immediately.
Syntax Errors and What They Cause
| Mistake | Example | Effect |
|---|---|---|
| Two SPF records | Two TXT values starting v=spf1 |
permerror |
| Missing or misspelled version | v=spf 1 ... or spf1 ... |
No SPF record found (none) |
| Typo in mechanism name | inlcude:_spf.google.com |
permerror |
| Space after colon | include: _spf.google.com |
permerror |
| More than 10 lookups | Many includes | permerror |
| Include of a domain without SPF | include:old-vendor.example |
permerror |
all not last |
-all include:x.com |
Everything after all ignored |
+all or no all |
v=spf1 include:x.com |
Open policy or neutral for strangers |
Redirect with an all |
redirect=x.com ~all |
redirect ignored |
| Unbroken string over 255 bytes | One huge quoted value | Rejected by DNS host, or record fails to publish |
With DMARC enforced, an SPF permerror can get legitimate mail rejected if DKIM does not align either.
How to Verify Your Syntax
- Paste your domain into the SPF checker. It shows the parsed record, the lookup count and any syntax errors.
- If you are building or rewriting a record, use the SPF generator so qualifiers and ordering are right the first time.
- Send a test message to a mailbox you control and read the
Authentication-Resultsheader with the email header analyzer. You should seespf=pass.
Frequently Asked Questions
What is the correct format of an SPF record?
It begins with v=spf1, followed by space-separated mechanisms such as ip4:, include: and mx, and normally ends with ~all or -all. It is published as a single TXT record at the domain.
What is the difference between ~all and -all?
-all tells receivers that unlisted servers are unauthorized and should fail. ~all marks them as suspicious but not outright failed. With DMARC enforced, the practical difference is small, since DMARC decides the final action.
Should I use include or redirect?
Use include to add third-party senders to your own record. Use redirect only when a domain has no senders of its own and should adopt another domain's policy entirely.
Can I have more than one SPF record?
No. Only one TXT record per domain name may start with v=spf1. Merge all senders into one record; two records cause a permerror.
How long can an SPF record be?
Each quoted string is limited to 255 bytes, but a record can contain several strings that receivers concatenate. Keep the full record comfortably under about 450 characters and under 10 DNS lookups.
Is the ptr mechanism still allowed?
It is still valid syntax but deprecated by RFC 7208 and should not be used. Replace it with explicit ip4, ip6 or include terms.
Where do I find my SPF record?
It is a TXT record in your domain's DNS zone, starting with v=spf1. Look it up with the SPF checker or by querying TXT records for your domain.
Do I need an SPF record if I only use Gmail or Microsoft 365?
Yes. Both providers give you an include to publish, and Gmail and Yahoo expect bulk senders to authenticate with SPF and DKIM. Without it, your mail is more likely to land in spam.
Does SPF stop spoofing on its own?
No. It checks the hidden envelope address and does not tell receivers what to do with failures. DMARC with an enforced policy closes that gap.
Why does SPF pass but DMARC fail?
Usually because SPF validated a different domain from the visible From address, such as a vendor's bounce domain. DMARC needs alignment, so DKIM signing with your own domain has to cover that sender.
Next step: Run your record through the SPF checker now, or request a free email audit if you want someone to review SPF, DKIM and DMARC together.