What it means
SPF answers exactly one question: was this IP address allowed to send mail using this domain as the envelope sender? You answer it in advance by publishing a TXT record on the domain, and every receiving server evaluates that record at connection time. The whole standard, RFC 7208, is a small grammar for expressing the sentence "these hosts yes, everything else no".
The word envelope is doing heavy lifting there. SMTP has two layers, and they are routinely different. The envelope is what the two servers say to each other: MAIL FROM:<bounces@pinlyx.com>, which becomes the Return-Path and is where bounces go. The message headers are what the human reads: From: hello@pinlyx.com. SPF only ever looks at the envelope. A phishing message can pass SPF with a perfectly legitimate envelope on a domain the attacker owns while displaying your brand in the From line, and SPF has no opinion about that at all. That gap is the reason DMARC was written.
Reading a record, token by token
A record is a version tag, then an ordered list of mechanisms, each with an optional qualifier. Evaluation stops at the first mechanism that matches, which means order is semantics, not style.
The four qualifiers:
+pass. The default, so it is almost always omitted.-fail. A hard no. This is what you want on the finalall.~softfail. "Probably not authorised, but accept and mark it." A transition state, not a destination.?neutral. Explicitly no opinion, treated the same as having no record.
There are also two modifiers rather than mechanisms. redirect= replaces the entire evaluation with another domain record, and is only sensible when many domains share one policy. exp= names a TXT record whose text is returned in the rejection message, which is useful for a helpdesk and invisible to everyone else.
The 10-lookup budget, and how teams blow it
This is the part that breaks production. RFC 7208 caps the number of DNS-querying mechanisms evaluated for a single check at ten. include, a, mx, ptr and exists each count, and an include also drags in whatever that record spends. A single large provider include can consume three or four on its own. There is a second, quieter limit of two void lookups, which are queries that return no record.
Cross the limit and the result is permerror. That is not a soft warning: under DMARC a permerror is not a pass, so a domain whose only aligned authentication was SPF starts failing outright, for every message, the moment somebody adds one more vendor. And it can happen without you touching your own record, if a provider expands the record you include.
Four ways out, in order of preference:
- Delete what you no longer use. Most oversized records contain includes for tools nobody has logged into for years.
- Split by subdomain. Marketing sends from
mail.example.com, the product fromnotify.example.com, the helpdesk fromsupport.example.com. Each gets its own record with its own budget, and a reputation problem in one does not follow the others. - Replace mx and a with literal ip4 and ip6. These cost nothing.
- Flatten as a last resort. Resolving the includes yourself and pasting the IPs works, but the record then goes stale silently when the provider renumbers, so it needs automation and monitoring, not a one-off copy and paste.
A worked failure
A team sends transactional mail through one provider, campaigns through a second, invoices through an accounting SaaS, and calendar invites through a workspace suite. Each vendor onboarding page says "add this include to your SPF record", so the record ends up with five includes plus an mx. The workspace include alone expands into four lookups. The eleventh lookup pushes the whole evaluation to permerror, and because the campaign vendor uses its own bounce domain, DKIM was the only aligned signal there anyway. Invoices, which were only ever authenticated by SPF, start landing in spam. Nothing in the invoice system changed. The fix was to move invoices to billing.example.com with a two-mechanism record of its own.
What a failure looks like in the logs
SPF problems surface as 5.7.x rejections and as an Authentication-Results header on anything that did get through. Gmail is explicit about it, Outlook less so, and both will usually accept a first offence and start rejecting once the pattern repeats. Whenever you are chasing a deliverability complaint, get a raw message from the recipient and read that header before changing anything.
What SPF does not do
- It does not stop display-name spoofing. A message from
attacker@gmail.comwith the display name "Finance Department" passes SPF for gmail.com and always will. - It does not survive forwarding. See the FAQ. This is not a bug you can configure around.
- It does not protect the message body. Nothing in SPF detects modification. That is DKIM.
- It is not a reputation system. Passing SPF gets you evaluated, not delivered. Volume, complaints and engagement decide the rest.
Related concepts
- DKIM: the signature-based check that keeps working after a forward.
- DMARC: the layer that connects an SPF pass to the From address a human reads.
- Bounce rate: an SPF regression shows up here within hours.
- Domain warm-up: publishing SPF is step zero of any warm-up plan.
- Cold outreach: sending from a subdomain with its own SPF record is standard practice.
How Pinlyx handles it
When you attach a sending domain, we resolve the record you publish and count the lookups the way a receiver would, then tell you how many of the ten you have spent before your first campaign goes out. Outbound mail uses a bounce subdomain under your own domain rather than a shared vendor domain, so the SPF pass aligns with the From header and satisfies DMARC on its own. Bounces come back to that subdomain, get classified by enhanced status code, and land on the contact record.