Skip to content
Control Plane Labs

SPF record

Lists the hosts allowed to send mail using a domain in the SMTP envelope sender.

Last updated July 27, 2026

Zone-file example

example.com.    3600    IN    TXT    "v=spf1 mx include:_spf.provider.net -all"

Typical uses

  • Authorising a hosted mail provider to send using your domain
  • Authorising marketing, ticketing, and monitoring platforms that send on your behalf
  • Publishing v=spf1 -all on names that never send mail
  • Feeding the SPF half of DMARC alignment

When it breaks, check

  • Only one v=spf1 record may exist per name; two is a permerror, not a merge
  • Evaluation is capped at 10 DNS-querying mechanisms, and include: chains blow through it
  • -all asks receivers to reject unlisted senders, ~all only marks them
  • SPF checks the envelope sender, not the From: header a recipient sees

What the SPF record does

An SPF policy is a small program. Mechanisms are evaluated in order and the first one matching the connecting address decides the result, with a trailing all catching the rest. ip4: and ip6: match literal addresses, a and mx match whatever those records resolve to, and include: pulls in another domain’s policy wholesale.

The identity checked is the envelope sender from the SMTP MAIL FROM command, not the From: address a human reads. A forwarded message keeps its From: and acquires a new envelope sender, so SPF breaks on forwarding by design. That gap is what DMARC alignment exists to close.

TXT record syntax

The value is one quoted string beginning v=spf1, followed by space-separated mechanisms, each optionally prefixed with a qualifier: + pass, - fail, ~ softfail, ? neutral. A bare mechanism defaults to pass. There is no dedicated record type any more: type 99 existed, and RFC 7208 §3.1 deprecated it in favour of publishing in TXT. Exactly one v=spf1 record may exist at a name; two is a permanent error, not a union of the pair.

; mechanisms are evaluated left to right, first match wins
example.com. 3600 IN TXT "v=spf1 mx ip4:203.0.113.0/24 include:_spf.provider.net -all"

; a name that never sends mail
parked.example.com. 3600 IN TXT "v=spf1 -all"

; INVALID: two v=spf1 records at one name is a permerror, not a merge
; example.com. 3600 IN TXT "v=spf1 include:vendor-a.net ~all"
; example.com. 3600 IN TXT "v=spf1 include:vendor-b.net ~all"

Common uses

The realistic job of SPF is authorising the handful of platforms that send as you: the mail provider, the transactional sender, the CRM, the ticketing system. Each arrives with an include: to paste in, and the set grows quietly until something breaks. Publishing v=spf1 -all on names that never send is the higher-value half of the work, since a hard fail there has no false positives.

Troubleshooting

The most common real-world failure is the lookup limit. RFC 7208 §4.6.4 caps evaluation at ten DNS-querying mechanisms — include, a, mx, ptr, exists, and the redirect modifier — counted across the whole nested tree, not just the record you wrote. Exceed it and the result is permerror, which many receivers treat as a failure, so adding one more vendor breaks mail that worked yesterday. Count the expansion, not your own line.

The trailing qualifier is the other conscious choice. -all asks receivers to reject unlisted senders and will bite on forwarded mail; ~all merely flags them. Under DMARC the difference matters less than people assume, because alignment does the real work.

# the policy itself
dig example.com TXT +short | grep -i 'v=spf1'

# expand every include: and count DNS-querying mechanisms against the limit of 10
dig _spf.provider.net TXT +short

# type 99 is deprecated; nothing should answer here
dig example.com TYPE99 +noall +answer

The defining RFC

SPF is RFC 7208, a Proposed Standard obsoleting the earlier experimental RFC 4408. Section 3.1 deprecates the dedicated SPF resource record, type 99, and requires publication in a TXT record; section 4.6.4 sets the ten-lookup limit behind most production breakage, and section 8 defines each result code. The retired type is still listed, marked obsolete, in the IANA DNS Parameters registry. Check a policy with the DNS lookup tool.

Reference and tooling

Every record type and its assigned numeric value is listed in theIANA DNS Parameters registry. To query a live zone from the browser, use theDNS lookup tool. If the record you are chasing is TLS-related, the TLS inspector andCertificate Transparency lookup are usually the next two stops.

Other record types