All tips
SPF 5 min read

What SPF actually does

SPF authorises servers, not messages, and it checks the envelope sender rather than the From address your recipient sees. That explains most SPF confusion.

Sender Policy Framework is a single DNS TXT record listing the servers permitted to send mail on your domain's behalf. When a server connects and offers a message, the receiver takes the connecting IP address, looks up your record, and walks through it left to right until something matches. The result feeds into the receiver's filtering decision and, if you publish DMARC, into the policy you have asked receivers to enforce.

That is the whole mechanism. Almost every difficulty people run into with SPF comes from one of three places: which address it actually checks, how quickly the lookup budget runs out, and what it cannot do at all.

It checks the envelope, not the header

SPF is evaluated against the MAIL FROM address supplied during the SMTP conversation. That address goes by several names: the envelope sender, the bounce address, the Return-Path. It is not the From address your mail client displays, and for most hosted senders the two differ by design.

Two different addresses in one message

MAIL FROM: bounces@mail.vendor.example   <- SPF checks this
From: newsletter@example.com             <- your recipient sees this

A marketing platform sets the envelope sender to its own bounce domain so that delivery failures come back to its infrastructure rather than your mailbox. SPF then passes for the vendor's domain while your brand sits in the From header, entirely unverified. Nothing is broken, and nothing about that pass says anything about the address the recipient reads.

This is precisely the gap DMARC closes, by requiring the SPF-checked domain to align with the visible From domain before the pass counts for anything. If that idea is new, alignment is the concept worth reading next.

Anatomy of a record

v=spf1 ip4:203.0.113.10 include:_spf.google.com include:sendgrid.net -all
  • v=spf1 is the version tag. Required, and always first.
  • ip4: and ip6: authorise a literal address or CIDR range. These use no DNS lookup.
  • include: defers to another domain's SPF record, which is how hosted senders are added.
  • a and mx authorise the addresses behind the domain's own A or MX records.
  • -all closes the record: anything not matched above fails.

Every mechanism can carry a qualifier: + for pass (the default, so it is almost always omitted), - for fail, ~ for softfail, and ? for neutral. In practice the only one you write deliberately is the one on the final all, and choosing between -all and ~all is a decision worth making consciously rather than inheriting from a vendor's setup guide.

How receivers evaluate it

Evaluation stops at the first mechanism that matches the connecting IP. Order therefore matters, and anything written after the all mechanism is dead text that will never be reached. This is the most common reason a freshly added vendor does not work: the include went on the end, after all, where nothing evaluates it.

The check produces one of seven results, and it is worth knowing them because they appear verbatim in Authentication-Results headers:

  • pass: the IP is authorised.
  • fail: the IP is not authorised, and the record says so explicitly with -all.
  • softfail: not authorised, but the record asks for delivery anyway, via ~all.
  • neutral: the record makes no assertion, via ?all.
  • none: the domain publishes no SPF record at all.
  • permerror: the record is broken. Two SPF records, a syntax error, or more than ten DNS lookups.
  • temperror: a transient DNS failure. The receiver may retry.

permerror is the one that catches people out. It is not a soft warning: DMARC counts it as an SPF failure, and nothing in your mail client will tell you it is happening. Only your aggregate reports will.

One record, and only one

A domain may publish exactly one SPF record. Adding a second, which usually happens when a new vendor's instructions are followed literally rather than merged into what is already there, produces a permanent error. Receivers do not combine them. When you onboard a service, merge its mechanisms into the existing record instead, and check your lookup budget before you do.

What SPF cannot do

SPF authorises servers. It says nothing about the content of a message, nothing about who wrote it, and nothing about whether the message was altered in transit. It also does not survive most forwarding, because the forwarding server relays from its own IP address, which your record has never heard of. That is working as designed rather than a bug, and it is the single strongest argument for making sure DKIM signs everything before you enforce a DMARC policy.

It also protects only the domains you publish it on. Every domain you own that never sends mail should carry a record authorising nothing, v=spf1 -all, because an unprotected parked domain is a free spoofing opportunity.

Checking your own

Paste a domain into the SPF tool to see the record broken out mechanism by mechanism, with a running DNS lookup count against the limit of ten. If the count is close to the limit, or the record ends in something other than -all or ~all, those are the two things worth fixing first.

Check your SPF record and lookup count
spfbasicsreturn-path