# What Is an SPF Record? Format, Syntax and the 10-Lookup Limit Explained

Source: https://truvocyber.com/blog/what-is-an-spf-record
Published: 2026-09-20
Topic cluster: Cybersecurity

> What is an SPF record? The v=spf1 format and syntax, an annotated SPF record example, -all vs ~all, and the RFC 7208 10-lookup limit that breaks records.

An SPF record is a DNS TXT record, published at a domain and starting with `v=spf1`, that lists the IP addresses and services allowed to send email using that domain in the SMTP envelope sender. A receiving mail server compares the connecting IP against the list and returns pass, fail, softfail or neutral. SPF is defined in RFC 7208 (April 2014), and a record with a duplicate or more than 10 DNS lookups returns permerror and authorizes nobody.

At a glance

- **Where the record lives**: One TXT record at the name used in the envelope sender (`example.com`, or a sending subdomain), TXT only per RFC 7208 section 3.1, which dropped the dedicated SPF record type (99) from SPF version 1
- **Record format**: `v=spf1` first, then mechanisms left to right, each with an optional qualifier, ending in `all` or `redirect=`
- **What it authenticates**: The domain in the envelope sender (RFC5321.MailFrom, seen as Return-Path) and the HELO hostname
- **What it does not authenticate**: The From header a recipient reads, the message content, or mail that has been forwarded
- **The limit**: 10 DNS lookups per evaluation (RFC 7208 section 4.6.4); over the limit returns permerror

## What is an SPF record for: naming the servers allowed to use a domain in the envelope sender

An SPF record answers one question a receiving server asks during the SMTP handshake: is the IP address connecting to me allowed to use this domain in the `MAIL FROM` command? That domain is the envelope sender, called RFC5321.MailFrom in the specification and visible after delivery as the Return-Path header. It is the address bounces go to, and it is often different from the From address a person sees.

RFC 7208 section 2.3 recommends checking the HELO hostname the sending server announces, and section 2.4 requires verifiers to check the `MAIL FROM` identity unless the HELO check already produced a definitive result. When the envelope sender is empty, as it is for bounce notifications, the verifier checks `postmaster@` the HELO hostname instead.

The SPF result is a statement about authorization, not about the message. Section 2.6 of RFC 7208 lists the possible results: none, neutral, pass, fail, softfail, temperror and permerror. The overview of [how SPF, DKIM and DMARC work together](/blog/spf-dkim-dmarc-how-email-authentication-works) covers where that result goes next.

## SPF record format: version, mechanisms, qualifiers and modifiers

An SPF record is a single string of space-separated terms, and the terms fall into three kinds: a version tag, mechanisms and modifiers. The version tag `v=spf1` must be the first term. RFC 7208 section 4.5 discards any TXT record that does not begin with exactly `v=spf1`, so `v=spf10` breaks the record, and so does anything placed before the version tag.

Mechanisms are tests against the connecting IP, evaluated left to right. RFC 7208 section 4.6.2 states that when a mechanism matches, processing stops and that mechanism's qualifier becomes the result; when it does not match, evaluation moves to the next term. The first match wins, so order matters. The eight mechanisms are `all`, `include`, `a`, `mx`, `ptr`, `ip4`, `ip6` and `exists`.

Qualifiers are a single character in front of a mechanism that decides the result when it matches:
SPF qualifierResult when the mechanism matchesTypical use`+` (default when omitted)pass`ip4:203.0.113.10` and `+ip4:203.0.113.10` mean the same thing`-`fail`-all` to reject every unlisted sender`~`softfail`~all` during rollout, before every sender is confirmed`?`neutral`?all` to express no opinion; rarely appropriate

Modifiers are `name=value` pairs that add information rather than testing the IP. RFC 7208 defines two: `redirect=` hands the evaluation to another domain's record when nothing else matched, and `exp=` names a TXT record whose text is returned as the explanation for a fail. Section 6 allows each once; a duplicate produces permerror.

If no mechanism matches and there is no `redirect=`, RFC 7208 section 4.7 returns neutral, as if `?all` had been written. A record with no `all` term therefore protects nothing.

## An annotated SPF record example, mechanism by mechanism

A working SPF record example for a domain that sends through Google Workspace, a marketing platform and one self-hosted server looks like this:

```
example.com.  IN  TXT  "v=spf1 ip4:203.0.113.10 ip6:2001:db8::/32 a mx include:_spf.google.com include:mail.marketingvendor.example -all"
```

Read left to right: version 1; the IPv4 address 203.0.113.10 may send; any address in the IPv6 block 2001:db8::/32 may send; the A and AAAA records of `example.com` may send; the MX hosts of `example.com` may send; anything Google's or the marketing vendor's SPF record authorizes may send; everything else fails.
SPF mechanismWhat it matchesCounts toward the 10-lookup limit`ip4:<address or CIDR>`The connecting IP is the address, or is inside the IPv4 rangeNo`ip6:<address or CIDR>`The connecting IP is the address, or is inside the IPv6 rangeNo`a` or `a:<domain>`The connecting IP is one of the A or AAAA records of the domain (defaults to the current domain)Yes`mx` or `mx:<domain>`The connecting IP is an address of one of the domain's MX hosts; each MX may resolve to at most 10 addressesYes`include:<domain>`The other domain's SPF record returns pass for this IP; a fail there does not fail the outer record, evaluation just continuesYes, plus every lookup the included record performs`exists:<domain>`An A record exists for the constructed name, usually built with macrosYes`ptr` or `ptr:<domain>`The reverse DNS name of the IP resolves back to it and ends in the domain; RFC 7208 section 5.5 says it SHOULD NOT be publishedYes`all`Always matches; used last as the defaultNo`redirect=<domain>` (modifier)Replaces the evaluation with the other domain's record when no mechanism matched; ignored if `all` is presentYes

The `a` and `mx` terms in the example are redundant if the same hosts are already listed by IP, and each spends a lookup. `include` asks whether the other record would pass this IP; only a pass counts.

## The SPF 10 DNS-lookup limit in RFC 7208, and why a record over it authorizes nobody

RFC 7208 section 4.6.4 caps the terms that trigger DNS queries at 10 per evaluation, and an implementation that exceeds the cap MUST return permerror. The counted terms are the `include`, `a`, `mx`, `ptr` and `exists` mechanisms and the `redirect` modifier. The `ip4`, `ip6` and `all` mechanisms and the `exp` modifier do not cause a lookup during evaluation and are not counted.

The count is cumulative through the include chain. `include:_spf.vendor.example` spends one lookup itself, then every `include`, `a` and `mx` inside the vendor's record adds to the same total. Five SaaS senders with two or three nested includes each can pass 10 with only five terms in the published record.

Key insight

**An SPF record over 10 lookups authorizes nobody.**

Permerror is the RFC 7208 section 2.6.7 result for a record that could not be interpreted, not a pass for the senders that were listed. Under DMARC, permerror is not a pass, so every message from that domain depends on DKIM alone.

Section 4.6.4 adds two smaller limits. Each `mx` term may cause at most 10 address lookups, and implementations SHOULD limit *void lookups*, queries that return no records or a name error, to two, with permerror beyond that. Two `a` or `exists` terms that return nothing can break a record that is otherwise well under 10.

## How to keep an SPF record under 10 lookups

Staying under the 10-lookup limit means spending lookups only on senders that need them, and four techniques cover most cases.

1. **Remove includes for services that no longer send.** A vendor dropped two years ago is still costing lookups, and its record may have grown since.
2. **Replace stable includes with the provider's published IP ranges.** `ip4` and `ip6` terms cost nothing. This is called flattening, and its cost is maintenance: when the provider changes its ranges the flattened record is stale, so it suits providers with rarely changing ranges rather than large platforms that shift addresses.
3. **Give third-party senders a subdomain.** A marketing platform sending with `news.example.com` in the envelope gets its own SPF record there, with its own 10-lookup budget, and a vendor's include chain growing past the limit affects only that subdomain.
4. **Drop `a`, `mx` and `ptr` where they add nothing.** If the mail servers are already listed by IP, `a` and `mx` are duplicates. `ptr` should not be published at all.

SPF macros, defined in RFC 7208 section 7, substitute connection details such as the sending IP into a domain name, typically with `exists:`, so one lookup can answer for many senders. Some managed SPF services use them to sidestep the limit; a domain with a handful of senders rarely needs them.

## -all vs ~all vs ?all in an SPF record, and how DMARC changes the choice

The final `all` term decides what happens to a server the record did not list, and the three usual qualifiers ask for three different treatments. `-all` returns fail, an explicit statement the server is not authorized. `~all` returns softfail, which RFC 7208 section 2.6.5 calls a weak statement that the host is probably not authorized. `?all` returns neutral, no opinion either way.

RFC 7208 leaves the handling of every result to the receiver. Section 8.4 leaves the handling of fail to local policy and says a receiver that chooses to reject during the SMTP transaction SHOULD use a 550 reply; section 8.5 says receivers SHOULD NOT reject solely on softfail. A domain with `~all` and no DMARC record has told receivers little more than one with `?all`.

DMARC does not look at the qualifier. RFC 9989 sections 4.4.2 and 5.3.5 count SPF toward a DMARC pass only when it produces a pass result for the `MAIL FROM` domain and that domain aligns with the From header; fail, softfail, neutral, none and permerror are all the same to DMARC. Once a domain publishes DMARC at quarantine or reject, the DMARC policy, not the SPF qualifier, is what a receiver's local policy consults for an unlisted sender.

Key insight

**With DMARC enforced, the DMARC policy decides what happens to unlisted senders; the SPF qualifier only matters at receivers that stop at SPF.**

`-all` is still the target state, because filters that apply SPF without DMARC may treat fail and softfail differently, and security questionnaires often ask whether the record ends in `-all`. Publish `~all` while DMARC aggregate reports confirm every legitimate sender, then move to `-all`. The guide to [what DMARC is](/blog/what-is-dmarc) covers alignment and the policy levels in full.

## What an SPF record does not do, and why DKIM and DMARC are still needed

An SPF record authenticates an address the recipient never reads, and that one fact explains its three gaps. Nothing in RFC 7208 ties the envelope sender to the From header: an attacker can send from a domain they control, pass SPF for it, and put any other domain in the From field, which RFC 7208 section 11.2 acknowledges directly.

Forwarding is the second gap. A forwarding server connects to the final receiver with its own IP, which is not in the original domain's SPF record, so SPF fails for legitimate mail. Message content is the third: SPF makes no statement about headers or body, so a passing message may have been altered or carry a forged Reply-To.

DKIM (RFC 6376) closes the content gap by signing the message with a key the domain publishes, and the signature survives forwarding because it travels with the message. DMARC closes the From-header gap by requiring the SPF or DKIM domain to align with the From domain and by publishing a policy for failures. The companion post on [what DKIM is](/blog/what-is-dkim) covers the signature and its keys.

## Common SPF record mistakes that produce permerror or no protection

The SPF record mistakes below each produce either a permerror, which authorizes nobody, or a record that is valid and protects nothing.

- **Two SPF records at one name.** RFC 7208 section 4.5 returns permerror when more than one `v=spf1` record is found. It commonly happens when a provider's setup guide says *add this TXT record* and the include is added as a second record instead of merged into the existing one.
- **`+all` at the end.** It matches every IP with a pass, so every server on the internet is authorized. It typically gets added in a hurry to fix a deliverability problem and stays.
- **No `all` term and no `redirect=`.** The default result is neutral, so the record expresses no policy.
- **`ptr` mechanisms.** RFC 7208 section 5.5 says they SHOULD NOT be published; they are slow, unreliable and spend lookups.
- **A typo in an include domain.** `include:_spf.googel.com` points at a name with no SPF record, and RFC 7208 section 5.2 turns that into permerror for the whole evaluation. Section 4.6.4 separately caps void lookups at two.
- **More than 10 lookups.** Permerror, and no sender is authorized.
- **A string over 255 characters.** DNS caps each character-string in a TXT record at 255 octets. RFC 7208 section 3.3 says a longer record is split into multiple quoted strings that the receiver concatenates without adding spaces; a DNS console that does not split the string may truncate or reject it. Section 3.4 says the DNS answer SHOULD fit in 512 octets and gives 450 octets, counting the name and every TXT record at that name, as the working guideline.
- **`redirect=` alongside `all`.** RFC 7208 section 5.1 ignores any `redirect` when `all` is present.

Key insight

**Two SPF records is the same as none.**

A domain that adds a second record to onboard a vendor has, from that moment, no working SPF for any sender, including the ones that were fine before.

## How to check and generate an SPF record

An SPF record can be checked with a DNS query for the domain's TXT records, and a purpose-built tool saves the lookup arithmetic. The [SPF checker](/tools/spf-checker) reads a domain's public TXT records over DNS over HTTPS, picks out the `v=spf1` record, reports which services it authorizes, how it ends and how many lookups it consumes, and sends no mail. Each finding is mapped to SOC 2 CC6.1, CC6.7 and CC7.2 and ISO 27001:2022 A.5.14 and A.8.20.

The [SPF record generator](/tools/spf-record-generator) assembles a record in the browser from the mechanisms added, counts lookups as each one goes in and shows when the total approaches the 10-lookup limit; the finished string is copied into DNS as a TXT record on the domain itself. Once it is live, the [DMARC checker](/tools/dmarc-checker) shows whether a DMARC record exists at `_dmarc.<domain>` and which policy it declares. The [free security tools](/tools) hub collects the SPF, DKIM, DMARC and MX lookups in one place.

### Bring the SPF record under the limit

Truvo consolidates senders as part of an effective security program and hands over the evidence.[Book Your Strategy Call](/contact-us)

## Frequently asked questions about SPF records

### What is an SPF record example?

A minimal SPF record for a domain that sends only through Google Workspace is `v=spf1 include:_spf.google.com -all`. It authorizes every server Google lists in its own SPF record and fails everything else. A domain that also sends from its own server adds an `ip4:` term before the `-all`.

### How many SPF records can a domain have?

Exactly one. RFC 7208 section 4.5 says a name with more than one record starting `v=spf1` produces permerror, so none of the listed senders are authorized. Every provider's include belongs in that one record. A subdomain that sends with its own name in the envelope gets its own single record.

### What does -all mean in an SPF record?

`-all` is the `all` mechanism with the fail qualifier. It always matches, so a server that reached it without matching an earlier mechanism receives an SPF fail, an explicit statement from the domain owner that the server is not authorized. `~all` returns softfail instead, and `?all` returns neutral.

### What is the SPF 10 lookup limit?

RFC 7208 section 4.6.4 limits the `include`, `a`, `mx`, `ptr` and `exists` mechanisms and the `redirect` modifier to 10 DNS lookups per evaluation, counted through every nested include. `ip4`, `ip6` and `all` are not counted. Exceeding the limit returns permerror, which means the record authorizes no one.

### Does SPF work without DMARC?

Yes, in the sense that receivers still evaluate the record and return a result. But SPF alone covers only the envelope sender, and RFC 7208 defines no required handling for any result, so a receiver may accept a message that failed SPF. DMARC ties the SPF result to the From address a recipient sees and tells receivers what to do when it fails.

{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What is an SPF record example?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "A minimal SPF record for a domain that sends only through Google Workspace is v=spf1 include:_spf.google.com -all. It authorizes every server Google lists in its own SPF record and fails everything else. A domain that also sends from its own server adds an ip4: term before the -all."
      }
    },
    {
      "@type": "Question",
      "name": "How many SPF records can a domain have?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Exactly one. RFC 7208 section 4.5 says a name with more than one record starting v=spf1 produces permerror, so none of the listed senders are authorized. Every provider's include belongs in that one record. A subdomain that sends with its own name in the envelope gets its own single record."
      }
    },
    {
      "@type": "Question",
      "name": "What does -all mean in an SPF record?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "-all is the all mechanism with the fail qualifier. It always matches, so a server that reached it without matching an earlier mechanism receives an SPF fail, an explicit statement from the domain owner that the server is not authorized. ~all returns softfail instead, and ?all returns neutral."
      }
    },
    {
      "@type": "Question",
      "name": "What is the SPF 10 lookup limit?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "RFC 7208 section 4.6.4 limits the include, a, mx, ptr and exists mechanisms and the redirect modifier to 10 DNS lookups per evaluation, counted through every nested include. ip4, ip6 and all are not counted. Exceeding the limit returns permerror, which means the record authorizes no one."
      }
    },
    {
      "@type": "Question",
      "name": "Does SPF work without DMARC?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes, in the sense that receivers still evaluate the record and return a result. But SPF alone covers only the envelope sender, and RFC 7208 defines no required handling for any result, so a receiver may accept a message that failed SPF. DMARC ties the SPF result to the From address a recipient sees and tells receivers what to do when it fails."
      }
    }
  ]
}
