← Back to news

SPF Record Syntax: Mechanisms, Qualifiers, Modifiers, and Macros

dmarcguard.io|30 points|7 comments|by meysamazad|Aug 3, 2026

SPF Record Syntax: Mechanisms, Qualifiers, Modifiers, and Macros

A Comprehensive Guide to RFC 7208

SPF (Sender Policy Framework) records are structured as a single DNS TXT entry. They must begin with the version identifier v=spf1, followed by a series of space-delimited terms. These terms consist of mechanisms (which may have qualifiers) and modifiers. The receiving mail server evaluates these terms from left to right, stopping at the first match.

Example of a Complete Record

v=spf1 ip4:192.0.2.0/24 include:_spf.example.com -all

In the example above, the domain authorizes a specific /24 subnet and a third-party service, while explicitly failing all other sources.

All governing rules are found in RFC 7208, published in April 2014. This reference covers every mechanism, qualifier, modifier, and macro, including evaluation logic and DNS constraints.


SPF Record Syntax at a Glance

An SPF record is essentially a string within the RDATA of a TXT record. Its grammar is composed of three distinct elements:

  1. Version Tag: Must be exactly v=spf1. If a record starts with v=spf10, it is ignored entirely (§4.5).
  2. Mechanisms: These are tested against the connecting client's IP address to determine a match (§4.6.2).
  3. Modifiers: These provide additional metadata and are not used for matching (§6).

Grammar Summary (§3 & §4.6.1)

PartFormatRoleRFC Section
Versionv=spf1Mandatory start; identifies the record§4.5
Mechanism[qualifier]name[:arg][/cidr]Validates the client IP§4.6.2
Qualifier+, -, ~, ?Defines the result if the mechanism matches§4.6.2
Modifiername=valueExtra info (max one of each type)§6

Evaluation Logic

The receiver's evaluation routine, known as check_host(), follows a strict process:

  • Terms are separated by spaces.
  • Mechanism names are case-insensitive.
  • Any term lacking =, :, or / is treated as a mechanism (§4.6.1).

Warning: A single syntax error invalidates the entire record. If check_host() detects a malformed term, it immediately returns a PermError without evaluating any other parts (§4.6). This is why a tiny typo can break email delivery for an entire organization.


SPF Mechanisms

There are eight mechanisms in total. RFC 7208 §5 categorizes them into Framework Mechanisms (all, include) and Designated-Sender Mechanisms (a, mx, ptr, ip4, ip6, exists).

Mechanism Reference Table

MechanismSyntaxMatch ConditionDNS CostRFC §
allallAlways matchesNo§5.1
includeinclude:domainReferenced record returns PassYes§5.2
aa[:domain][/cidr]IP matches domain's A/AAAA recordsYes§5.3
mxmx[:domain][/cidr]IP matches domain's MX hostsYes*§5.4
ptrptr[:domain]Reverse DNS matches target domainYes§5.5
ip4ip4:network[/cidr]IP is within the IPv4 rangeNo§5.6
ip6ip6:network[/cidr]IP is within the IPv6 rangeNo§5.6
existsexists:domainDomain has any A recordYes§5.7

*MX mechanisms trigger one MX query and up to 10 address queries; exceeding this limit results in a PermError (§4.6.4).

SPF Logic Diagram

Detailed Mechanism Breakdown

The all Mechanism

The all mechanism is a "catch-all" that always matches. Consequently, it must be placed at the end of the record (§5.1).

  • Any terms appearing after all are ignored.
  • If all is present, any redirect= modifier is ignored.
  • Records lacking all or redirect= default to a Neutral result (§4.7).

The include Mechanism

This triggers a recursive check of another domain's SPF record. It matches only if that external record returns a Pass (§5.2).

Nuance: The RFC admits "include" is a misleading name. If an included record contains a -all (Fail), it does not cause the primary record to fail. It simply means "no match here; continue to the next term in the primary record."

Critical Note: If the domain specified in an include has no SPF record, the result is a PermError (§5.2).

a and mx Mechanisms

  • a: Matches if the client IP is an A or AAAA address of the target domain (§5.3).
  • mx: Matches if the client IP is an address of one of the target domain's MX hosts (§5.4).
  • Defaults: Both use the current domain if no argument is provided.
  • CIDR Support: They support dual CIDR suffixes. For example, a/24 checks the first 24 bits, and a:example.com/24//64 specifies different prefixes for IPv4 and IPv6.

ip4 and ip6 Mechanisms

These test if the client IP resides within a literal network using a colon (e.g., ip4:192.0.2.0/24).

  • Incorrect Syntax: ip4=192.0.2.0/24
  • Defaults: Omitted CIDR lengths default to /32/32 for IPv4 and /128/128 for IPv6.
  • Restriction: Truncated addresses (like 192.0.2) are forbidden (§5.6).
  • Efficiency: These are the most efficient mechanisms as they incur zero DNS cost.

The exists Mechanism

This mechanism constructs a domain name and performs an A record query. If any A record exists—regardless of the IP address—it matches (§5.7). This is always an A query, even for IPv6 connections.

When paired with macros (§7), exists allows for dynamic authorization. By publishing per-IP hostnames in a controlled zone, a domain can authorize specific IPs without listing them explicitly in the SPF record (a technique used by Salesforce).


SPF Validation Checklist

  • Does the record start with v=spf1?
  • Are all terms separated by single spaces?
  • Is the all mechanism placed at the very end?
  • Does the total number of DNS lookups stay 10\le 10?
  • Are ip4 and ip6 mechanisms using colons (:) rather than equals signs (=)?