SPF Syntax

SPF syntax

An SPF record is a single TXT record at the apex of a domain. It is one line of text, made of three things in order: a version tag, a sequence of mechanisms, and a closing rule.

Worked example for isidoregroup.com:

v=spf1 include:spf.protection.outlook.com -all

Read left to right. The version tag declares the policy language. Each mechanism is an authorization rule. The final -all is the catch-all for anything none of the prior rules matched.

This lesson walks through every piece you will see in the field.

The version tag

v=spf1

Always first, always exactly this. RFC 7208 reserves v=spf1 and no other version exists in production. If you see something that doesn’t start with v=spf1, it is not an SPF record — it is some other TXT record at the apex.

Cathedra identifies SPF records by checking str_starts_with(trim($txt), 'v=spf1'). Anything else in the TXT set is ignored by the SPF check.

Mechanisms

A mechanism is a rule that says “consider mail authorized if it matches this.” Six mechanisms appear regularly. All of them can be prefixed with a qualifier (covered below) to change what “matches” means.

ip4 and ip6

Authorize a specific IPv4 or IPv6 address or range.

ip4:198.51.100.7
ip4:198.51.100.0/24
ip6:2001:db8::/32

The most direct mechanism — no DNS lookup, just a comparison against the sender’s IP. Use when you know the sending IP and it is stable. Common for on-prem mail servers, dedicated SMTP relays, and self-hosted transactional senders.

a

Authorize the IPs that the domain’s own A or AAAA records resolve to.

a
a:mail.isidoregroup.com

Bare a means “the A record of the domain this SPF record is published for.” a:hostname means “the A record of that specific hostname.” Each a mechanism counts as one DNS lookup against the 10-lookup limit.

mx

Authorize the IPs of the domain’s MX servers.

mx
mx:isidoregroup.com

Bare mx means “the MX hosts of this domain, then resolve each to an IP, and authorize all of them.” Useful when the inbound mail server also sends outbound on the same IPs. Each mx mechanism counts as one lookup, and the hosts it returns also count. An MX set with three hosts consumes one mx lookup plus three A-record lookups.

include

Defer the decision to another domain’s SPF record.

include:spf.protection.outlook.com
include:sendgrid.net

This is the workhorse mechanism. When the receiver evaluates include:spf.protection.outlook.com, it fetches that domain’s SPF record and evaluates it as if it were inlined. A pass in the included record counts as a pass for the parent.

Every include counts as one lookup. The lookups inside an included record also count against the parent’s total. This is how the 10-lookup limit gets hit — three or four include mechanisms, each pulling in two or three more, and you are over the cap.

redirect

Replace this record’s evaluation with another domain’s.

redirect=spf.example.com

redirect is rare. It is used when one organization manages SPF policy centrally for many domains. Unlike include, redirect discards the current record entirely and uses the target’s all rule too. Most techs will see this once a year.

Counts as one DNS lookup.

ptr

Authorize the IP if its reverse DNS resolves back to a name under the domain.

ptr
ptr:isidoregroup.com

ptr is discouraged by RFC 7208 because it is slow and expensive on the receiver. Some receivers ignore it entirely. You will occasionally see it on older records. If you find one in a client’s SPF, plan to remove it during the next edit.

Counts as one lookup, but the receiver may do additional reverse lookups on top.

exists

Authorize if a given hostname resolves at all (any A record). Rare. Used for some custom anti-abuse setups. Counts as one lookup.

Qualifiers

Every mechanism can be prefixed with a qualifier that changes how it scores. The qualifier is a single character before the mechanism.

Qualifier Result on match Meaning
+ Pass The default. +include:... is equivalent to include:....
- Fail Reject. The receiver should refuse the message.
~ Softfail Accept but mark suspicious. Usually delivered to spam.
? Neutral No opinion. Treat as if SPF said nothing.

Qualifiers are only meaningful on the closing all and, occasionally, on a specific ip4 or include you want to override. In day-to-day work, you will only set qualifiers on all.

The closing all

all matches everything. Whatever qualifier you put on it decides what happens to senders that did not match any prior mechanism.

v=spf1 include:spf.protection.outlook.com -all

The -all here means: “If the connecting IP did not match the Outlook include, reject the message.” That is the enforcing posture and it is what Cathedra wants to see.

The four all variants and what they mean:

Ending Effect on unauthorized senders Cathedra status
-all Reject pass
~all Soft-fail (usually spam) warning, medium
?all Neutral, treated as no SPF error, critical
+all Allow everyone error, critical
(none) Default neutral per RFC warning, medium

The next lesson goes through each of those with the exact Cathedra finding text. Memorize the table above before moving on.

A realistic record, dissected

A real Isidore client running M365 with SendGrid for transactional mail and Constant Contact for marketing:

v=spf1 include:spf.protection.outlook.com include:sendgrid.net include:spf.constantcontact.com -all
  • v=spf1 — version tag.
  • include:spf.protection.outlook.com — Microsoft’s published sender IPs. One lookup.
  • include:sendgrid.net — SendGrid’s published sender IPs. One lookup.
  • include:spf.constantcontact.com — Constant Contact’s published sender IPs. One lookup.
  • -all — reject anything else.

Three direct lookups, plus whatever each include pulls in. In practice this record consumes about six to eight of the ten available lookups. Adding two more major senders without flattening will push it over the cap. That is lesson 3.4.

What you should remember

  • Every SPF record is v=spf1 + mechanisms + a closing all.
  • include is the most common mechanism. Every include is a DNS lookup against the 10-lookup ceiling.
  • The qualifier on all is the enforcement posture: -all rejects, ~all soft-fails, ?all and +all allow.
  • Cathedra reads the record and grades it on these mechanisms alone. No SMTP probe, no live test.

Next: what Cathedra reports for each all posture, with the exact finding text you will see.


Cathedra alignment: SpfRecordCheck.php — every mechanism Cathedra inspects is defined here