DMARC Engine
Home/Blog/RFC 7208: the SPF standard explained
Blog

RFC 7208: the SPF standard explained

The SPF specification in plain British English: the record format, every mechanism, the four qualifiers, the eight result codes, the 10-lookup and void-lookup limits, and the macro language. Real example records throughout, plus exactly why SPF speaks for the return-path and never the visible From.

22 June 2026 · 6 min read

RFC 7208: the SPF standard explained

RFC 7208 is the standard that defines SPF (Sender Policy Framework). It was published in April 2014 and replaced RFC 4408. In short: a domain publishes one TXT record starting v=spf1; a receiver evaluates its terms left to right against the connecting IP address; the first matching term decides the result; and the result is one of seven values. Two limits break more real records than anything else: ten DNS-querying terms, and two lookups that return nothing.

What SPF checks

SPF checks whether the IP address delivering a message is allowed to send for the domain in the envelope sender, the address in the SMTP MAIL FROM command, which later appears as Return-Path:. RFC 7208 also recommends checking the HELO name the server gave. When the MAIL FROM is empty, as it is for bounce messages, SPF uses postmaster@ plus the HELO name instead.

SPF never looks at the From: header your recipient sees. Linking SPF to that address is DMARC's job, through alignment. Header From versus envelope From explains the difference.

The record

DNS record
v=spf1 include:_spf.google.com include:sendgrid.net ~all
  • The record is a TXT record. RFC 7208 retired the separate SPF record type.
  • It must start with v=spf1.
  • A domain may publish one SPF record. If a receiver finds more than one, the result is permerror.
  • Terms are separated by spaces and evaluated left to right until one matches.
  • A record longer than 255 characters is published as several strings in one TXT record, which receivers join with nothing added between them, so put any needed space inside a string.

Terms are either mechanisms, which can match the connecting IP, or modifiers, which set parameters and never match.

Qualifiers

Each mechanism can start with a qualifier that sets the result when it matches:

QualifierResultMeaning
+ (the default)passAuthorised
-failExplicitly not authorised
~softfailProbably not authorised, but do not reject on SPF alone
?neutralThe domain makes no assertion

So ~all is the all mechanism with the softfail qualifier.

Mechanisms

MechanismMatches whenDNS lookup?
allAlways. It ends the record and sets the result for everything not matched earlierNo
ip4: / ip6:The IP is in the address or range. Without a prefix length, a single address (/32 or /128)No
aThe IP is one of the domain's A or AAAA addressesYes
mxThe IP is one of the addresses of the domain's MX hostsYes
include:The named domain's SPF record returns passYes
exists:The named domain has any A record; usually built with macrosYes
ptrReverse DNS of the IP falls under the domain. RFC 7208 says it SHOULD NOT be publishedYes

Three behaviours worth knowing:

  • Anything after all is never evaluated, because all always matches. ~all include:vendor.example never reaches the include.
  • include: only matches on a pass. If the included record returns fail, softfail or neutral, the include simply does not match and evaluation carries on.
  • +all authorises the whole internet. Never publish it.

Modifiers

  • redirect=domain replaces the current record with another domain's record, but only when nothing in the current record matched. It is ignored if the record contains all, so use one or the other.
  • exp=domain points to an explanation string a receiver may show when the result is fail.

Unknown modifiers are ignored rather than treated as errors.

The seven results

ResultMeaning
noneNo SPF record was found, or the domain does not exist
neutralA ? term matched. RFC 7208 says receivers must treat it exactly like none
passThe IP is authorised
failA - term matched, usually -all
softfailA ~ term matched, usually ~all
temperrorA temporary problem, usually a DNS timeout. The receiver may try again later
permerrorThe record cannot be evaluated: two SPF records, a syntax error or a limit exceeded

permerror is always the domain owner's to fix. Repeated temperror usually means DNS problems at your provider or at a domain you include. Neither none nor neutral counts as a pass for DMARC.

The limits that break real records

Ten DNS-querying terms. During one evaluation, include, a, mx, ptr, exists and redirect together must not exceed ten, counting everything nested inside includes. One more returns permerror. ip4, ip6 and all cost nothing.

Nesting is what catches people out. Some providers flatten their own records to save you lookups; at the time of writing, _spf.google.com lists its addresses directly, while Mimecast's global include nests eight regional includes. Check your real total with the SPF checker.

Address lookups inside mx. Each MX host may resolve to at most ten addresses. Beyond that, the mx mechanism returns permerror. For ptr, names beyond the first ten are ignored.

Two void lookups. RFC 7208 says evaluation SHOULD stop with permerror after more than two lookups that return no answer (the name does not exist, or exists with no records). The usual cause is an include: pointing at a provider you stopped using whose record has been removed.

The standard fix for the ten-lookup limit is to replace includes with the addresses they resolve to, known as flattening. Flattened lists go stale when a provider changes its addresses, so they need re-checking; hosted SPF flattens your record and re-resolves it automatically.

Macros

RFC 7208 includes a macro language, written %{letter}, used mainly inside exists:. For example, exists:%{ir}.%{v}._spf.example.com builds a lookup name from the connecting IP. Most domains never need macros; SPF macros explained covers the syntax and the risks.

Walking a record like a receiver

For a connection from 209.85.220.41 with MAIL FROM:<alerts@example.com> and this record:

DNS record
v=spf1 ip4:198.51.100.0/24 include:_spf.google.com include:sendgrid.net -all
  1. ip4:198.51.100.0/24 does not contain the address. No lookup used.
  2. include:_spf.google.com is fetched and evaluated. Google's record lists 209.85.128.0/17, so it returns pass and the include matches. Result: pass.
  3. include:sendgrid.net and -all are never reached.

Because evaluation stops at the first match, a message from an early sender may never reach the later lookups. Do not rely on that: a sender further down, or a spoofed message that matches nothing, walks the whole record, so keep the full total within ten.

Where SPF stops

SPF answers one question about the envelope sender and returns one of seven results. It says nothing about the visible From address and nothing about what a receiver should do with a fail. DKIM signs the message, and DMARC ties SPF and DKIM to the From address and tells receivers what to do; DMARC versus SPF versus DKIM compares the three.

Run your domain through the SPF checker to see your current record, its lookup count and any permerror conditions.

Share

See where your domain stands today

Run a free DMARC scan, then let us take you to enforced p=reject with no email outage.