All posts
July 23, 2026

SPF Explained: The Record, the 10-Lookup Limit, and the Merge Rule

What SPF actually checks (not the From line you see), the syntax piece by piece, the one-record and ten-lookup rules that break real setups, and why forwarding defeats it by design.

TL;DR — SPF is a DNS TXT record listing the servers allowed to send mail from your domain's envelope address. One record per domain, at most 10 DNS lookups, ending in -all. It checks the invisible envelope sender — not the From line people see — which is why SPF alone stops nothing and needs DMARC to matter. Here's the syntax, the failure modes we actually see, and the merge rule that prevents the classic self-inflicted outage.

What SPF actually checks (and what it doesn't)

When a server receives mail, the sending server announces an envelope sender (the Return-Path — where bounces go). SPF answers one question: is the connecting server's IP authorized by the envelope sender's domain?

Note what's missing: the From header — the address displayed in every mail client — is not part of that check. A spammer can pass SPF with their own domain in the envelope while showing ceo@yourdomain.com in the From line. Connecting the two is DMARC alignment's job; SPF is one input to it. This misunderstanding is the single most common reason people believe SPF "isn't working".

The record, piece by piece

yourdomain.com.   TXT   "v=spf1 include:_spf.yourprovider.com ip4:203.0.113.25 -all"

Read left to right; first match wins:

Part Meaning
v=spf1 Mandatory opener. Without it, receivers ignore the record.
include:_spf.provider.com Import the provider's authorized servers. This is how you authorize your mail host without knowing its IPs.
ip4: / ip6: Authorize an address or CIDR range directly — costs no DNS lookup.
a / mx Authorize the domain's A or MX targets. Rarely what you actually mean; each costs a lookup.
-all Everything not listed above: fail. The terminal verdict for everyone else.

-all vs ~all

~all (softfail) says "unlisted senders are suspicious"; -all (fail) says "unlisted senders are forged". With DMARC in place the practical difference shrinks — alignment failure is what triggers policy — but publish -all once you're confident your record is complete: it's the unambiguous statement, and some receivers do weight it. +all (allow everyone) appears in the wild more often than you'd hope; it announces that your domain performs no authentication at all.

The two rules that break real setups

One record. Exactly one.

The standard is blunt: multiple SPF records for one domain is a permanent error, evaluated as if you had none. This happens innocently — your mail host's wizard adds a record, your website builder adds another for its contact forms, and now both are void.

The fix is a single merged record:

"v=spf1 include:_spf.mailhost.com include:_spf.websitetool.com -all"

One v=spf1, every legitimate sender's mechanism, one -all. (This is also a thing to demand from any tool that "sets up SPF for you": it should merge into what exists, not overwrite it. Our own DNS automation merges for exactly this reason — we learned to treat an existing SPF record as something a customer's mail depends on, because it is.)

Ten lookups. Not eleven.

Every include:, a, mx, redirect and exists costs a DNS lookup, recursively — an include: whose own record contains three more include:s costs four. Past ten, evaluation stops with a permanent error, and your legitimate mail starts failing authentication at whatever receiver counted first.

Symptoms are maddeningly intermittent because different receivers cache differently. Audit with any online SPF-lookup counter, and fix by removing dead tools (the newsletter service you left in 2023 is still costing you three lookups), replacing a/mx vanity mechanisms with ip4: where stable, or — carefully — "flattening" an include into raw IPs (accepting that you now must track the provider's IP changes; only do this for providers that publish stable ranges).

Forwarding: the case SPF cannot survive

When someone auto-forwards your message onward, the forwarder's server delivers mail carrying your envelope domain — an IP your record never authorized. SPF fails, correctly by its own logic, on completely legitimate mail. This isn't fixable inside SPF (SRS rewriting exists, but it's the forwarder's job, and it changes the semantics). It's why authentication needs a second, forwarding-proof leg — DKIM survives forwarding because the signature travels inside the message — and why DMARC accepts either leg passing.

A sane record for a typical domain

Most personal/small-business domains on a hosted mail provider need exactly this:

"v=spf1 include:<your provider's SPF include> -all"

Add an include: per additional legitimate sender (transactional service, newsletter tool), audit yearly, and resist every temptation to add mechanisms "just in case" — SPF is an allowlist, and allowlists earn their keep by being short.

Checking your work

Send a message to a Gmail address and open "Show original": you'll see SPF: PASS (or not) with the checked IP and domain, plus the DKIM and DMARC verdicts alongside — thirty seconds, no tools. For the record itself, any SPF validator will parse mechanisms and count lookups before you commit.


The rest of the series: DKIM explained · DMARC explained · MX records explained · and the full picture in Email on Your Own Domain: The Complete 2026 Guide. On MailHow these records are generated per domain and SPF is merged into your existing record automatically.