Notix
Learn

SPF: which servers may send for your domain.

An SPF record is a line of DNS that lists the servers allowed to send mail for a domain. A receiving server reads it, compares the address that connected against the list, and records pass, fail, softfail or neutral. That is the whole mechanism. What people get wrong is which domain is being checked, how many DNS lookups a record is allowed to cost, and what SPF proves about the From address a reader sees, which is less than it seems. The setup walkthrough for all three records is on SPF, DKIM and DMARC; this page is SPF itself.

What SPF checks: the envelope sender, not the From.

A message carries two sender addresses. The envelope sender is the address given in the SMTP MAIL FROM command, which the receiving server stores as the Return-Path header and uses for bounces. The header From is the address written inside the message, the one a mail client shows. They can differ, and for a sending service they usually do: the envelope sender is on a subdomain the service controls, so bounces come back to it, while the header From is your address.

SPF checks the envelope sender. Per RFC 7208, a verifier evaluates the HELO name first if it wants to, and must evaluate the MAIL FROM identity unless the HELO check already gave a definitive answer. The header From is never consulted. So when a service asks you to publish SPF on mail.yourdomain.com, that is the domain it will put in the envelope, and that is the record the receiver reads.

Record syntax, with a worked example.

An SPF record is a TXT record whose text starts with v=spf1, followed by terms separated by spaces, evaluated left to right until one matches. Here is a company that sends from its own mail server range and from Google Workspace, and wants everything else refused:

A complete SPF record on the bare domain
acme.com.  IN TXT  "v=spf1 ip4:203.0.113.0/24 include:_spf.google.com -all"

Read it as: any address in 203.0.113.0/24 passes; otherwise go and evaluate Google’s own record and pass if it does; otherwise fail. Each term is a mechanism, optionally prefixed by a qualifier.

SPF mechanisms and the DNS lookups each one costs
TermWhat it matchesDNS lookups
ip4:203.0.113.0/24Any address in this IPv4 range is authorised.None
ip6:2001:db8::/32The same for an IPv6 range.None
aThe A or AAAA addresses of the domain (or of the name given, a:mx1.acme.com).One
mxThe addresses of every MX host of the domain.One, plus up to ten address lookups
include:other.exampleEvaluate that domain's record; a pass there is a match here.One, plus whatever that record spends
exists:nameMatches when the name resolves at all. Rare; used for macro tricks.One
ptrReverse lookup of the sending IP. Deprecated by the RFC; do not publish it.One, plus address lookups
allMatches everything. Goes last, with the qualifier that says what to do.None
redirect=other.exampleA modifier, not a mechanism: use that domain's record instead of the rest of this one.One

Qualifiers: what a match means.

The character in front of a mechanism says what result a match produces. It is optional and defaults to +, so include: and +include: are the same thing. In practice the qualifier only ever matters on the final all, because that is the term that catches everything the list did not.

SPF qualifiers and the result each produces
QualifierResultMeaning
+ (or nothing)passThe sender is authorised.
-failThe sender is not authorised; the receiver may reject.
~softfailProbably not authorised; accept, but mark it.
?neutralThe domain says nothing either way.

Why do sending services tell you to end with ~all rather than -all? Because the record they ask for sits on a name they will be sending from, and they cannot see what else you will put on it later. A hard fail turns a forgotten sender into rejected mail; a soft fail turns it into a mark the receiver weighs along with everything else. Once DMARC is published, its policy decides what happens to mail that fails authentication, and the SPF qualifier stops carrying the decision on its own.

The ten-lookup limit, and how includes spend it.

RFC 7208 section 4.6.4 limits the terms that cause a DNS query to ten per evaluation: include, a, mx, ptr, exists and the redirect modifier count; ip4, ip6 and all do not. Cross the limit and the result is permerror, which receivers treat as if the domain had no valid SPF at all. The limit exists so a record cannot be used to make a receiver do unbounded work.

The part that catches people is that an include is not one lookup. It is one lookup for the record it names, plus every lookup that record makes in turn, recursively. A typical office suite’s include is two or three deep. Add a CRM, a helpdesk, a newsletter tool and a transactional service to the same record, each with its own nest of includes, and ten arrives quickly:

Counting lookups across nested includes
v=spf1 include:_spf.google.com include:sendgrid.net include:spf.protection.outlook.com a mx -all
       ^ 1 lookup (+2 inside)   ^ 1 (+1 inside)     ^ 1 (+2 inside)               ^ 1 ^ 1
                                                       total so far: 10, and the next include is a permerror

To count yours, resolve each include and add up what it pulls in; several free SPF checkers do this and show the tree. To get back under the limit, remove services you no longer send from first. Then replace an include with the provider’s published ip4 and ip6 ranges only where the provider commits to stable ranges, because a flattened record goes stale the day the provider moves. The cleanest fix is structural: give each sending service its own subdomain with its own record, so no single name has to carry them all. That is what a mail subdomain does.

Two smaller limits sit beside the big one. Each mx mechanism may resolve at most ten address records, and a verifier should stop after two lookups that return nothing. Keep the record small enough for a UDP answer as well, which the RFC puts at roughly 450 octets for the whole DNS response.

One record per name.

A name must not have more than one SPF record. RFC 7208 is explicit that a receiver finding two returns permerror, so a second v=spf1 TXT record does not add a sender, it disables authentication for the whole domain. When a provider’s instructions say “add this SPF record” and one already exists, merge the new include into the existing record. A record on a different name is a different record, which is the other reason a subdomain per service is the safe pattern.

The record Notix asks for.

When you add a domain in the dashboard, the DNS records it shows include a TXT record on the mail subdomain of that domain:

The SPF record the dashboard shows for a sending domain
mail.acme.com.  IN TXT  "v=spf1 include:amazonses.com ~all"

Notix puts mail.yourdomain.com in the envelope sender of everything it sends for you, so this is the record receivers evaluate. An MX record on the same name routes bounces back to the infrastructure Notix sends through, and the DKIM record on notix._domainkey signs the message so the visible From is covered too. Your bare domain’s SPF record, and the office suite already listed in it, are not touched. The dashboard checks the records after you add them and shows each one as pending or verified; the same status is on the domain in the API.

What SPF does not do.

SPF proves that the server which delivered a message was allowed to send for the domain in the envelope. It proves nothing about the From address a reader sees, because that address is not checked. A spoofer can put a domain they own in the envelope, pass SPF for it, and write your domain in the header From. SPF also breaks on plain forwarding, because the forwarding server is not in your list, which is one reason receivers weigh a softfail lightly.

The fix for the first problem is alignment, which is DMARC’s job: it requires the domain that passed SPF, or the domain whose DKIM signature verified, to match the visible From. The fix for the second is DKIM, whose signature survives forwarding when SPF cannot. SPF is a third of the answer, and it is the third that is easiest to publish and easiest to get wrong. The other two are on DKIM and DMARC, and all three are set up together on SPF, DKIM and DMARC. The rules quoted here are from RFC 7208.

FAQ

Questions, answered.

What does an SPF record actually check?
Whether the server that connected to deliver a message is one the sending domain has listed. The domain being checked is the one in the SMTP envelope sender, the MAIL FROM address that becomes the Return-Path header, not the From address a person sees in their mail client. RFC 7208 checks the MAIL FROM identity, and the HELO name before it; it never looks at the visible From.
Why does SPF say too many DNS lookups, and how do I fix it?
RFC 7208 caps the terms that need a DNS query at ten per evaluation: include, a, mx, ptr, exists and redirect all count, and an include also spends every lookup inside the record it pulls in. Past ten the result is permerror, which receivers treat as no SPF at all. Fix it by removing services you no longer send from, replacing an include with ip4 and ip6 ranges where the provider publishes stable ones, and moving each sending service onto its own subdomain so no single record carries them all.
Should I end the record with ~all or -all?
-all tells receivers to fail anything not listed; ~all tells them to accept it but mark it. On a domain where every sender is known and the record is complete, -all is the stronger statement. Sending services usually ask for ~all on the subdomain they control, because a hard fail on a record they cannot see the rest of would bounce legitimate mail the moment you add another sender and forget to update it. Once DMARC is in place the difference matters less: DMARC's policy, not the SPF qualifier, decides what happens to mail that fails.
Can a domain have two SPF records?
No. RFC 7208 says a name must not have more than one record that the check would select, and a receiver that finds two returns permerror, which is worse than having none. If a provider tells you to add a second v=spf1 record, merge its include into the record you already have instead. A separate record on a different name, such as a subdomain, is fine, and it is the clean way to give each sending service its own.
Does SPF stop someone spoofing my From address?
Not on its own. SPF authenticates the envelope sender, and a spoofer can put any domain they control in the envelope while writing yours in the visible From. What stops that is DMARC alignment: DMARC requires the domain that passed SPF, or the domain that signed with DKIM, to match the visible From. SPF is one of the two ways to satisfy that, and DKIM is the other, which is why both are set up together.
What SPF record does Notix ask me to publish?
One TXT record on the mail subdomain of your sending domain, mail.yourdomain.com, with the value v=spf1 include:amazonses.com ~all, alongside an MX record on the same name for bounce handling. The dashboard shows the exact records for each domain you add and checks them for you. Because the record sits on the mail subdomain, the SPF record on your bare domain, the one Google Workspace or Microsoft 365 use, is left alone.

Add a domain and the records are written for you.

Notix shows the exact SPF, DKIM and DMARC records for each domain and checks them until they verify.