Chapter 01 · Authentication
RFC 7208

SPF — sender policy and the 10-lookup failure mode.

SPF is defined by RFC 7208 and is the oldest of the three authentication protocols a sender publishes. It is also the protocol whose failure mode is the quietest: a record that parses cleanly, looks correct to the operator, and silently returns permerror at the receiver because the DNS-lookup budget exceeded the protocol-mandated ceiling of ten.

What SPF actually proves

A receiving mail server, on inbound SMTP delivery, takes the domain in the envelope MAIL FROM address — the return-path — and performs a DNS TXT lookup against that domain to retrieve its SPF record. The record enumerates the IP addresses authorized to send on behalf of that domain. The receiver compares the connecting IP against this set. If the IP is authorized, SPF passes. If it is not, SPF fails.

What SPF proves is narrow: a specific IP is, or is not, on a list the domain owner published. SPF does not validate the visible From: header that the recipient sees. It does not cryptographically bind the message body to the sender. It does not survive any intermediate hop that rewrites the envelope. The protocol verifies a single property of a single SMTP connection — origin-IP authorization — and nothing more.

This narrowness is the reason DMARC (Chapter 3) exists. SPF on its own permits a spammer to send mail with From: ceo@yourbank.com from infrastructure whose own envelope domain passes SPF, because SPF never checks the header the human actually reads.

The record format

An SPF record is a DNS TXT record published at the root of the sending domain. There is no _spf subdomain (a frequent confusion with DMARC and DKIM). The record begins with the version token v=spf1 followed by a space-delimited sequence of mechanisms, each optionally prefixed with a qualifier. A minimal record:

example.com.  IN  TXT  "v=spf1 include:_spf.sendingplatform.com -all"

The receiver evaluates mechanisms left to right until one matches the connecting IP; the qualifier on the matched mechanism determines the verdict. If no mechanism matches, the trailing all mechanism — which matches everything — provides the default verdict. A record with no trailing all is technically valid but operationally broken: the no-match default becomes neutral, equivalent to having published no policy at all.

Only one SPF record per domain is permitted by RFC 7208 §3.2. A domain with two v=spf1 TXT records produces permerror at every receiver. The operator typically discovers this when adding a new sending platform via a second TXT entry — the prior record was never removed — and the sending estate goes dark for the next propagation window.

Mechanisms

The protocol defines a small set of mechanisms, each of which expresses a different way to match the connecting IP. The mechanisms that matter in practice:

ip4 and ip6

Direct IP authorization. ip4:198.51.100.0/24 authorizes a CIDR block of IPv4; ip6:2001:db8::/32 does the equivalent for IPv6. Neither consumes a DNS lookup, because the IP is encoded in the record. These are the cheapest possible mechanisms by lookup-budget accounting, and the form the record collapses to after flattening.

a and mx

The a mechanism authorizes the IPs returned by an A record lookup against the domain (the SPF record's own domain by default, or an explicit one via a:other.example.com). The mx mechanism does the same against the domain's MX records. Each consumes one DNS lookup; mx additionally consumes a lookup per MX target, with most receivers capping evaluation at ten targets.

These mechanisms are convenient for senders whose outbound mail originates from the same infrastructure as their inbound mail. They are dangerous for senders whose MX records point at a managed mailbox provider that does not send outbound mail on the operator's behalf — the mechanism silently authorizes the provider's entire inbound infrastructure as a legitimate sender.

include

The include:other.example.com mechanism delegates a portion of the SPF policy to another domain. The receiver performs a recursive SPF evaluation against the included domain and treats a pass there as a match. This is the mechanism third-party sending platforms publish in their setup documentation — the operator adds include:_spf.platform.example to authorize the platform without tracking its IP ranges by hand.

Each include consumes one DNS lookup at the surface, and the recursive evaluation consumes its own lookups against the same budget. This recursive cost is the single most important operational property of SPF, and the property most operators discover late.

exists

The exists:%{i}.lookup.example.com mechanism passes if a DNS A record exists at the constructed name. It is used to authorize IPs dynamically against an external database — by encoding the connecting IP into a hostname and asking DNS whether that hostname resolves. Rarely seen outside reputation-system implementations; mentioned here so the operator can recognize it when auditing a record. Each exists consumes one lookup.

ptr — and why it is deprecated

The ptr mechanism passes if the reverse DNS lookup on the connecting IP returns a hostname that, when forward-resolved, points back at the connecting IP and is a subdomain of the SPF-evaluated domain. RFC 7208 §5.5 explicitly deprecates it. The cost — a reverse lookup plus a forward verification per record — produces a denial-of-service surface the protocol authors deemed unacceptable. The mechanism appears in old records inherited from senders who configured SPF before 2014. It should be removed on sight.

Qualifiers

Each mechanism may be prefixed with a single-character qualifier that determines the verdict on match:

  • + (pass) — explicit authorization. The default; almost always omitted.
  • - (fail) — hard rejection. The IP is not authorized.
  • ~ (softfail) — soft rejection. Probably not authorized, but the sender requests leniency.
  • ? (neutral) — explicit non-statement. The domain owner declines to express a verdict.

The qualifier on the trailing all mechanism is the central policy decision in the record. -all instructs receivers that any IP not enumerated above is unauthorized. ~all instructs receivers that such mail is probably unauthorized but the sender is hedging.

The historical advice to publish ~all during initial deployment originated when receivers occasionally rejected hard-fail mail outright on SPF alone. That era is over. Modern receivers fold SPF into the DMARC verdict, and DMARC's policy tag governs enforcement. The practical difference between ~all and -all in 2026 is largely cosmetic at the receiver — both produce DMARC fail unless DKIM aligns — but at the sender's own record audit, -all reads as a deliberate policy statement while ~all reads as an unfinished deployment. For a cold-sending domain whose authentication estate is presumed final at first send, -all is the correct qualifier.

The 10-DNS-lookup limit

RFC 7208 §4.6.4 caps the total number of DNS lookups in a single SPF evaluation at ten. This includes lookups triggered by include, a, mx, exists, and the deprecated ptr. ip4, ip6, and all do not count.

If evaluation exceeds ten lookups, the receiver returns permerror. From the DMARC perspective, permerror is not a pass. The mail authenticates only via DKIM, if DKIM aligns; if it does not, the configured DMARC policy applies as if no SPF record existed at all.

The cap exists because SPF evaluation is performed inline during SMTP delivery. A receiver processing inbound mail at scale cannot afford an unbounded recursive DNS walk per message — a deliberately deep include chain would amplify a single connection into thousands of authoritative queries against the sender's infrastructure. The cap is a denial-of-service mitigation expressed as a lookup budget.

The budget is small relative to modern sending stacks. A typical B2B operator may run on a single domain: a corporate mail provider (one include, internally one to three further lookups), a transactional provider (one include, three to six further), a marketing platform (one include, two to four further), a calendar invite platform (one include, one to two further), and a support-tool reply address (one include). The arithmetic crosses ten between the third and fourth platform. The record looks correct — five clean include statements deployed exactly as each vendor specified — and silently returns permerror at every receiver from the day the fourth vendor was added.

Include-chain auditing

That a single include consumes one lookup at the surface and an unknown number of lookups inside its own record is the property that makes SPF deployment treacherous. A correct audit walks the chain recursively and counts every lookup against the budget. Tools for this exist in inbox-placement testing services and in the open-source ecosystem; the operator's job is to run one regularly, not estimate by inspection.

The internal contents of a vendor's include are not under the sender's control. A vendor may, during a quiet infrastructure migration, expand their internal record from three nested lookups to seven. The sender's record was at the edge before the migration; after, it is over. Nothing on the sender's side changed, and yet authentication began failing as soon as the vendor's TTL expired. This is the transitive-include problem, and it is the reason a one-time audit at deployment is insufficient — continuous monitoring of the recursive lookup count is the operational discipline that catches it.

SPF flattening

Flattening is the practice of replacing every include, a, and mx mechanism with the literal ip4 and ip6 ranges those mechanisms would have resolved to. The flattened record contains zero DNS lookups by construction and cannot exceed the budget regardless of how many platforms the operator authorized.

The tradeoff is maintenance. A third-party sender's IP ranges drift. The operator who flattened a vendor's include on Monday is publishing yesterday's IPs by Friday, and the gap manifests as SPF failures on newly routed traffic. The flattened record requires automated re-resolution — typically nightly — against the upstream targets, diffed against the current record and republished on change. This automation is the price of the lookup-budget escape.

The decision to flatten is correct when the include set exceeds the budget and cannot be reduced by removing vendors. It is wrong when the sender has fewer than four include mechanisms and the budget is not yet under pressure. Most cold-sending domains, configured cleanly, do not need flattening. Most corporate domains with mature SaaS estates do.

SPF and forwarders

A meaningful fraction of legitimate mail does not arrive at its final receiver directly from the original sender. A recipient may forward through a personal forwarding rule, a mailing-list server, a vanity-domain proxy, or a corporate alias that rewrites the envelope. In each case, the IP arriving at the final receiver is the forwarder's, not the original sender's. The original SPF record does not authorize it. SPF fails.

This is not a misconfiguration of either side. It is structural — the protocol authorizes the envelope-from domain against the connecting IP, and the connecting IP at the final receiver is no longer the original sender's. Roughly 3 to 8% of legitimate cold-sequence replies, in our observation, are forwarded through some intermediate hop, and SPF fails on every one.

The protocol that mitigates this is ARC (Chapter 6), which allows a forwarder to attest cryptographically that the message passed authentication at the moment it arrived. A downstream receiver that honors ARC can recover the original verdict despite the envelope rewrite. ARC adoption is not universal, and a sender deploying DMARC at p=reject on the basis of SPF alone — without DKIM, which survives most forwarders — will silently lose the forwarded fraction of their legitimate traffic.

SPF and DMARC alignment

DMARC requires that the domain SPF authenticated against — the envelope MAIL FROM domain — align with the domain in the visible From: header. Alignment is either relaxed (organizational domain match) or strict (exact match). The default is relaxed.

The envelope MAIL FROM domain matters more than the operator's casual mental model suggests. A sequencing platform that sets the envelope to bounce-12345.platform.example while the From: header reads operator@sendingdomain.com may pass SPF against the platform's record but fail DMARC alignment against the sender's — the authenticated domain and the header domain share no organizational root.

The fix is custom-return-path configuration: setting the envelope MAIL FROM to a subdomain of the sender's own domain, typically bounce.sendingdomain.com, which CNAMEs to the platform's bounce infrastructure. Authentication and alignment then occur against the same organizational domain. Most modern sequencing platforms expose this as a configurable option; the operator's job is to find it and set it before warmup begins.

The cold-sending domain pattern

A cold-sending domain is a separate organizational domain — not a subdomain of the corporate root — registered specifically to house outbound sequence traffic. Its SPF record should be as lean as the architecture permits: one sending platform, no transactional mail, no calendar invites, no marketing automation, no inheritance from the corporate record. The record consists of the version token, a single include for the sending platform, and a hard-fail trailing mechanism.

mail.sendingdomain.com.  IN  TXT  "v=spf1 include:_spf.platform.example -all"

One surface lookup, some number of nested lookups inside the platform's record, the budget not at risk. Adding a corporate mail provider's include to the cold-sending domain — because the operator wanted a one-off send from their corporate client to pass SPF — is the most common scope creep on the record, and the first mistake that takes the recursive lookup count from three to nine and starts the slide toward permerror.

Common deployment failures observed in production

  • Two SPF records on the same domain. The operator adds a new sending platform via a second TXT record without removing the existing one. RFC 7208 §3.2 mandates a single record; receivers return permerror. The operator typically discovers this when warmup mail stops being delivered three days into ramp.
  • Crossing the 10-lookup budget by transitive include expansion. The operator's surface-level record has four clean include mechanisms; the cumulative recursive lookup count is fourteen. The record looks correct, parses correctly, and silently returns permerror at every receiver.
  • Trailing ?all or no trailing mechanism. The default verdict on no-match becomes neutral, which is functionally equivalent to no policy at all. DMARC cannot enforce against a neutral SPF result. The record exists but enforces nothing.
  • Including the corporate mail provider on the cold-sending domain. The operator wants their personal client to be able to send from the cold domain on rare occasions, and adds the corporate include "just in case." The lookup count rises, the alignment surface widens, and a future audit cannot easily distinguish authorized cold traffic from authorized corporate traffic on the same domain.
  • Authorizing the mx of a mailbox provider as a sender. The operator adds mx to the record because they read it in a generic configuration template. The mechanism authorizes the entire inbound infrastructure of the mailbox provider — IPs that the sender does not control, that handle inbound mail for thousands of other tenants — as legitimate origins for the sender's domain.
  • Leaving ptr mechanisms in records inherited from older configurations. The mechanism is deprecated by RFC 7208 §5.5; many receivers ignore it; some interpret its presence as a configuration smell. It should be removed on sight, not retained for compatibility.
  • Misconfiguring the envelope return path on a third-party platform. The platform's default envelope domain does not share an organizational root with the visible From: header. SPF passes against the platform's domain, the operator's record looks fine, and DMARC alignment silently fails on every message. The operator's open rates are unaffected; the receiver's spam classifier is not.

Pre-deployment checklist

  • Exactly one v=spf1 TXT record at the sending domain root, verified by a separate DNS query
  • Total recursive DNS lookup count under ten, verified by an inbox-placement testing service or an open-source SPF parser
  • Trailing mechanism is -all, not ~all or ?all, and not absent
  • No ptr mechanism present
  • No mx or a mechanism unless the sender's mail flow actually originates from that infrastructure
  • Envelope MAIL FROM on every sending platform configured to a subdomain of the sender's own domain, for DMARC alignment
  • The sending platform's include documented in an internal runbook, with the date last verified against the platform's current setup documentation
  • A scheduled audit — monthly is reasonable — of the recursive lookup count, to catch transitive expansion by upstream vendors

Where SPF fits in the broader infrastructure

SPF on its own is not a deliverability protocol. It is one of two authentication primitives — the other being DKIM (Chapter 2) — that produce the input signals DMARC (Chapter 3) consumes when deciding whether to enforce the sender's published policy. A correctly configured SPF record does not produce primary-tab placement, does not survive forwarders, and does not on its own protect the sender's brand against impersonation. A misconfigured SPF record, however, breaks every protocol that depends on it, and in 2026 every protocol the major mailbox providers care about depends on it.

For a cold-sending domain specifically, SPF is the cheapest record to get right and the cheapest to get subtly wrong. The lean pattern — one include, hard-fail, no inheritance — is the configuration that survives both the deployment audit and the monthly lookup-budget review. The corporate-domain pattern, with its accumulating SaaS estate and its always-edging-toward-the-budget recursive lookup count, is a different problem with a different operational discipline, and one that should not be allowed to leak onto the sending tier.

Skip the setup

Allston Labs operates the full sending estate as a service.

We provision domains, configure the entire authentication record set, run warmup, and monitor reputation across providers. The stack lives under your entity. The engineer on call lives in your Slack.