The SPF Include Mechanism, Explained Properly

What include: actually does during SPF evaluation, why it's not the same as simply copy-pasting another domain's IP ranges, and where it commonly goes wrong.

📅 Published August 2026· ⏳ 14 min read· ✍️ ToolsNovaHub Editorial Team
🛠️ Related tool: Open SPF Lookup →

What include: Actually Evaluates

The include mechanism is the piece of SPF syntax that lets one domain delegate a portion of its sender authorization to another domain's record, and it's by far the most common mechanism in real-world SPF records because almost nobody sends all of their mail directly from infrastructure they own. When a receiving server hits include:example-vendor.com during evaluation, it doesn't just note the domain name and move on — it performs a full DNS lookup for example-vendor.com's own SPF TXT record, then evaluates that entire record's mechanisms exactly as if they'd been written inline, purely to determine whether the current sending IP produces a pass under that vendor's rules.

What comes back from that nested evaluation isn't the vendor record's own qualifier result in a literal sense — it's translated into a simple match or no-match signal for the include mechanism itself. If the included record's evaluation results in a pass for the IP in question, the include mechanism matches. Anything else — fail, softfail, neutral, or even the included record running out without matching — means the include mechanism itself simply doesn't match, and the parent record's evaluation moves on to whatever mechanism comes next.

ToolsNovaHub Pro Tip
Before adding a new vendor's include, resolve it yourself first and see how many lookups it actually costs. A vendor that looks like "just one include" in their setup docs can secretly nest through two or three more, quietly eating your lookup budget.
⚠️
Common Beginner Mistake
Treating a fail result inside an included record as if it fails your whole SPF check. It doesn't — a fail inside an include only means that particular mechanism doesn't match; your own record's later mechanisms still get evaluated normally.

Syntax and a Worked Example

The syntax is simple: include: followed immediately by a domain name, no spaces, case-insensitive. A typical multi-vendor record looks like this: v=spf1 include:_spf.google.com include:sendgrid.net include:mailgun.org ~all. Reading it left to right, a receiving server checking a message that claims to be from Google Workspace infrastructure will match on the first include and stop there — it never needs to evaluate the SendGrid or Mailgun includes at all for that particular message, since SPF evaluation halts at the first match.

This left-to-right, stop-at-first-match behavior matters more than it looks like it should. Ordering includes roughly by sending volume, with your highest-volume vendor first, has no effect on correctness but can meaningfully reduce the average number of lookups a receiving server performs across your actual mail traffic, since most checks will resolve on an early match rather than working through every include.

Include vs. Static IP Ranges vs. Redirect

ApproachStays Accurate Automatically?Lookup CostBest For
include:Yes1 + whatever the target record costsAny vendor that actively maintains and publishes one
Static ip4:/ip6:No — needs manual updates0Infrastructure you fully control, or lookup-constrained records
redirect=Yes1, replaces rest of recordFully delegating an entire domain's SPF policy to another, rare outside specific setups

Common Mistakes With Include

📁
Leftover Vendor Includes
Old marketing or CRM platforms you stopped using months ago, still sitting in the record and burning lookup budget for nothing.
🔄
Duplicate Includes
The same vendor added twice by different people at different times, often with slightly different subdomains that resolve to the same thing.
Wrong Include Domain
Copy-pasting a vendor's SPF include hostname incorrectly, which causes a permerror since the target domain won't publish a matching record.

What Breaks When an Include Domain Goes Away

An include is a live pointer, not a snapshot, and that cuts both ways. It's convenient because your record automatically reflects a vendor's current sending infrastructure without you touching DNS. But it also means your SPF evaluation now depends on that vendor's DNS zone continuing to exist and continuing to publish a valid record indefinitely. If a vendor is acquired, rebrands, or simply lets an old SPF include domain lapse, every domain still referencing it in an include mechanism will get a permerror on that mechanism the next time mail is evaluated — not a graceful "no longer applicable," but a hard error condition, because include specifically requires the target to resolve to a valid record.

This is a real, if uncommon, failure mode worth checking for periodically: audit your includes not just for relevance but for whether the target domains still resolve to valid SPF records at all, particularly for less actively maintained third-party tools.

How Include Interacts With the Lookup Limit

Every include mechanism costs at least one lookup against SPF's shared 10-lookup ceiling, and often considerably more once its own nested mechanisms are counted. Because include is simultaneously the most common mechanism in real-world records and the one most likely to hide additional recursive lookups inside it, it's also the single biggest contributor to records that accidentally exceed the limit. A record with what looks like a modest four or five include lines can easily resolve to 9, 10, or more actual lookups once every vendor's own record is expanded and counted.

Why Vendors Ask for an Include Instead of Publishing IPs Directly to You

It's worth understanding the vendor's side of this relationship, because it explains why include exists as a mechanism at all rather than every setup guide just listing IP ranges to paste in. A mail-sending vendor operating at any real scale is constantly adjusting its outbound infrastructure — adding capacity in a new region, rotating out address space that's picked up a bad reputation, migrating to new cloud provider ranges, or splitting traffic across additional pools for deliverability reasons. If every one of their customers had pasted static IPs into their own SPF records, none of those changes could happen without asking thousands of customers to manually update their DNS in lockstep, which is operationally unworkable at scale. Publishing a single SPF record at a stable include hostname and asking customers to reference it with include: turns that coordination problem into something the vendor can solve unilaterally, on their own timeline, without anyone else needing to do anything.

This is also why the include mechanism's "live pointer" behavior, which can feel like a downside when you're trying to reason about exactly what's authorized at any given moment, is actually the entire point of the design. The alternative — static, vendor-provided IP lists — is precisely what flattening produces, and precisely why flattening carries the ongoing maintenance cost it does.

Reading a Real Vendor's Include Chain

Take Google Workspace as a concrete example, since it's one of the most widely referenced includes in real-world records. A typical setup adds include:_spf.google.com to a domain's SPF record. Resolving that hostname's own TXT record doesn't return a flat list of IPs directly; historically it has returned a small number of further include mechanisms pointing at region- or purpose-specific sub-records, each of which is what actually contains the ip4 and ip6 ranges. The practical effect is that one line in your record, include:_spf.google.com, can expand through two layers of nested includes before reaching literal IP ranges — meaning that single include can cost three or four lookups against your budget, not one, once every layer is counted. This is exactly the kind of detail a naive top-level read of your own record will never surface, and exactly why recursive tooling matters more than manual inspection for anything beyond the simplest setups.

What "No Match" From an Include Actually Tells You

It's worth sitting with the earlier point about fail results inside an include a bit longer, because it trips people up in a specific way. Imagine your record is v=spf1 include:vendor-a.com include:vendor-b.com -all, and a message arrives from an IP that vendor-a.com's own record would explicitly mark with a hard fail for. That fail does not propagate upward as your record's overall result. What actually happens is: the include:vendor-a.com mechanism evaluates vendor-a.com's record, finds a hard fail for this IP, and translates that into "this mechanism does not match" — evaluation simply proceeds to include:vendor-b.com next, exactly as if vendor-a.com's record had said nothing about the IP at all. Only if none of your mechanisms match, all the way through, does your record's own trailing -all take over and produce the final fail. In other words, an included record's own qualifiers (pass, fail, softfail, neutral) only ever matter for producing a match or no-match signal for that one include mechanism — they never directly determine your record's ultimate outcome.

Keeping an Include Inventory

For any domain sending mail through more than two or three vendors, it's worth maintaining a simple standing record, outside of DNS itself, of what each include in your SPF record is for: which vendor, which product or team uses it, who owns that relationship, and roughly when it was added. This sounds like overhead for something that's "just DNS," but it's the difference between a five-minute decision when auditing the record later ("yes, still used, keep it") and a much slower, riskier one ("not sure if anything still depends on this, better leave it in just in case") that's exactly how records accumulate permanent bloat in the first place.

What Happens Mechanically Inside a Single Include Evaluation

It's worth breaking the include evaluation process into its literal steps, because the sequence explains several behaviors that otherwise seem arbitrary. First, the evaluator takes the domain named after include: and issues a DNS TXT query for it, exactly one query, which is the lookup that counts against your budget. Second, it inspects the returned TXT records and selects the one beginning with v=spf1 — if there isn't exactly one, that's a permerror right there, independent of anything else. Third, it evaluates that selected record's own mechanisms in order, recursively applying the same left-to-right, stop-at-first-match logic your top-level record uses, including recursively counting any further lookups those mechanisms trigger. Fourth, and this is the step people most often get wrong intuitively, it translates whatever qualifier that nested evaluation lands on — pass, fail, softfail, or neutral — into a simple binary signal for the include mechanism itself: pass becomes "this include matches," and everything else becomes "this include does not match, keep going." There is no fifth step where a fail inside the included record propagates outward as anything other than "no match here."

A Common Real-World Failure: The Renamed Vendor Include

One specific include-related failure worth knowing about by name, because it doesn't look like a typical SPF problem when it happens: a mail vendor rebrands, migrates to new infrastructure, or gets acquired, and in the process retires their old SPF include hostname in favor of a new one, sometimes with a transition period, sometimes without. If your record still references the old hostname after that domain stops resolving to a valid SPF record, you don't get a warning — you get a permerror the next time your record is evaluated, because include: specifically requires its target to resolve. What makes this failure mode particularly sneaky is that it can happen entirely without you doing anything, and the resulting bounce messages from receiving mail servers usually just say something generic about SPF failing, rarely pointing specifically at "your include target no longer has a valid record." Diagnosing it requires actually resolving each of your record's include targets directly and confirming each one still returns a valid v=spf1 TXT record, not just assuming that because it worked at setup time it still works now.

Comparing How Three Common Vendors Structure Their Includes

Vendor PatternTypical StructureApproximate Lookup Cost
Flat single-layer vendorOne include resolving directly to a list of ip4/ip6 ranges1 lookup
Regionally split vendorOne include resolving to 2–3 further region-specific includes3–4 lookups
Product-line split vendorOne include resolving to several includes, one per product line (transactional, marketing, etc.)4+ lookups, varies by how many product lines exist

None of this structure is visible from your own record's text — include:vendor.com looks identical regardless of which pattern the vendor actually uses internally. This is exactly why resolving a new vendor's include chain before adding it, rather than assuming "it's just one include" based on how it reads, is worth the extra few minutes.

Include Chains and Debugging Tools

When troubleshooting a record that includes several vendors, a tool that only reports your top-level record's syntax is of limited use, because the actual problem is very often buried two or three layers into one specific vendor's chain. What's actually useful is a tool that walks the entire tree exactly the way a receiving mail server would — following every include recursively, tallying the running lookup count as it goes, and flagging specifically which layer, if any, is contributing a void lookup or a missing record. Without that recursive view, a record that looks clean at the top level can be silently broken two levels deep, and no amount of staring at your own DNS zone will reveal it.

Include and the exp= Explanation Modifier, Together

A detail that rarely comes up until it actually matters: when an included record's own evaluation contributes to an eventual overall fail (via the parent record's trailing all mechanism, not the include itself), any exp= modifier that fires to produce a human-readable explanation is the one defined on whichever record's evaluation actually produced the final all match — typically the top-level record's own exp=, not one buried inside an included vendor's record. This matters for domain owners who've configured a custom rejection explanation: don't expect an included vendor's own exp= text to surface in your own domain's failure messages, since include's translation of the nested result into a simple match/no-match signal, as covered earlier, means the included record's own modifiers largely stay local to that nested evaluation rather than propagating outward.

A Practical Checklist for Adding a New Include

StepWhat to Check
1Confirm the exact hostname from the vendor's current official setup documentation, not an old support thread
2Resolve the target's TXT record directly and confirm it returns exactly one valid v=spf1 record
3Trace whether that record nests further includes, and if so, how many lookups the full chain costs
4Recalculate your total record's lookup count with the new include added, before publishing
5Check whether the vendor's own documentation flags their IPs as subject to frequent change

Skipping straight to step 4 without steps 1 through 3 is exactly how records end up with a mechanism that looked fine in isolation but pushed the total over budget once its full nested cost was actually accounted for.

Include Chains That Reference Each Other Indirectly

A less common but real pattern worth knowing about: two vendors you've both separately added as includes might, unknown to you, each reference a shared third-party infrastructure provider through their own nested includes. This doesn't cause any error — SPF has no problem evaluating the same underlying IP ranges twice through two different paths — but it does mean your effective lookup cost includes some redundancy that isn't obvious from looking at your own two top-level include lines. Discovering this kind of overlap generally requires actually tracing both chains fully rather than assuming two unrelated-looking vendor names mean two entirely independent lookup paths.

How Case Sensitivity Rules Apply to Include Domain Names

DNS domain names are case-insensitive by design, and this extends cleanly to how include: mechanisms are written and evaluated — include:Vendor.COM and include:vendor.com resolve identically, querying the same underlying DNS record regardless of capitalization used in the SPF record's text. This is worth knowing mainly because it means capitalization inconsistency across a record, while stylistically messy, never causes an actual functional problem the way a genuine typo in the domain name itself would. It's a good practice to keep casing consistent for readability during audits, but it's a cosmetic concern, not a correctness one.

Include and Subdomain-Specific Vendor Records

Some vendors publish their SPF include record not at their apex domain but under a dedicated subdomain specifically reserved for this purpose, such as spf.vendor.com or _spf.vendor.com rather than vendor.com directly. This is generally a deliberate choice on the vendor's part, keeping their SPF-specific DNS record cleanly separated from whatever else lives at their main apex domain, and functions identically to an apex-domain include from the perspective of your own record — you simply reference whatever exact hostname the vendor's documentation specifies, subdomain or not, and evaluation proceeds exactly the same way regardless of which part of the vendor's domain structure the record happens to live under.

A Deeper Look at What "Selecting the Correct Record" Means at Each Domain

When include: queries a target domain for its SPF record, that domain's DNS zone may return multiple TXT records at the queried hostname for entirely unrelated reasons — domain verification strings for various third-party services, DKIM records if the query happens to overlap with an unusual zone structure, or other TXT-based configuration entirely unrelated to SPF. RFC 7208 is explicit that exactly one of the returned TXT records must begin with the literal string v=spf1 for evaluation to proceed; if zero records match that prefix, or if more than one does, the result is a permerror, precisely mirroring the same "must have exactly one SPF record" rule that applies to a domain's own top-level record. This means a vendor's include target domain is just as susceptible to the multiple-SPF-records failure mode as any other domain would be, and it's specifically the vendor's own responsibility to keep their include-target zone clean of duplicate v=spf1 entries — a responsibility outside your direct control, but worth knowing about as one more category of failure that traces back to the vendor's side rather than your own configuration.

Include Chains and the Practical Limits of Manual Auditing

Beyond a certain chain depth, manually tracing an include's full nested structure by hand becomes genuinely impractical, not just tedious. A chain three or four levels deep, where each level might branch into two or three further includes, can represent dozens of individual DNS records that would all need to be manually queried, read, and cross-referenced to build a complete picture by hand. This is precisely the point at which automated recursive tooling stops being a convenience and becomes a practical necessity — not because the underlying logic is complex to understand conceptually, but because correctly executing that logic across a genuinely deep, branching chain, entirely by hand, introduces enough opportunity for simple human error (missing one nested include, miscounting one branch) that the manual result can't be trusted with the same confidence as a tool that mechanically walks the entire tree without skipping anything.

How Include Behaves When the Same Domain Appears More Than Once in a Chain

An edge case worth understanding: if the same domain ends up being referenced more than once within a single record's full recursive expansion — for instance, because two different top-level includes both happen to nest down into a shared third domain somewhere in their own chains — each occurrence is still evaluated as its own separate lookup by a strictly compliant implementation, since SPF evaluation doesn't inherently deduplicate or cache results across different branches of the same overall evaluation tree. This means a shared dependency reached via two different paths genuinely does cost two lookups, not one, even though the underlying DNS record being queried is identical both times. Being aware of this is useful specifically when trying to understand why a record's actual lookup count came out higher than expected based on a mental model that assumed shared dependencies would somehow be counted only once.

Related Reading in This Series

For the full mechanics of why SPF caps total lookups and how to count them, see SPF 10 Lookup Limit. For how include compares to fully delegating your record with redirect, read SPF Redirect Explained. If your record already has too many includes, SPF Record Optimization covers the trimming process directly. To see exactly what your current includes resolve to, open SPF Lookup.

Reviewed by: ToolsNovaHub Editorial Team📅 Last updated: August 2026📜 Sourced from: RFC 7208

ToolsNovaHub tools are built and independently maintained with a focus on accurate, no-signup network and security utilities. Spotted an error? Let us know.

📋 Related Tools & Guides Comparison

ResourceTypeLink
SPF LookupToolOpen Tool →
SPF 10 Lookup LimitGuideRead Guide →
SPF Redirect ExplainedGuideRead Guide →
SPF Record OptimizationGuideRead Guide →
DKIM LookupToolOpen Tool →
Try it yourself — 100% free
🚀 Open SPF Lookup

🔗 More Guides

FAQ

It tells the evaluator to fetch a separate domain's SPF record and evaluate that record's mechanisms as part of determining whether the current sending IP is authorized, then return a specific match result back to the parent evaluation.
No. include performs a live, recursive lookup of the target domain's current SPF record every time your record is evaluated, so it always reflects whatever that vendor currently publishes, unlike a static copy-paste of IPs.
Because their sending IP ranges change over time as they scale infrastructure, rotate providers, or add regions, and an include lets every customer's SPF stay accurate automatically without needing to be manually updated whenever that happens.
No, this is a specific technical nuance: an include only ever contributes a match/no-match signal upward based on whether the target record's mechanisms produced a pass. A fail or softfail inside the included record does not propagate as an overall fail for your record — it's simply treated as no match, and evaluation continues to the next mechanism.
Yes, in the specific sense that SPF evaluation is left-to-right and stops at the first mechanism that matches. Placing a broad include before a narrower one can mean the narrower one, and its more accurate 'all' qualifier, never actually gets evaluated for a given sending IP.
The result is a permerror for that mechanism, since include: specifically requires the target to publish a valid SPF record; a missing record is treated as an error condition, not simply a non-match.
Technically the syntax allows it, but it accomplishes nothing useful and just adds an unnecessary recursive lookup against your own zone; there's no scenario where self-including improves an SPF configuration.
There's no separate limit on nesting depth specifically, but every level of nesting still consumes lookups against the shared 10-lookup ceiling, so deep nesting from certain vendors can exhaust your budget even with very few top-level include lines.
Not in a way that causes an error — each include is evaluated independently and only contributes a pass signal for its own listed IPs. But an accumulation of many broad vendor includes can widen your effective authorized sending range more than intended.
Use include if the vendor explicitly publishes and maintains one for this exact purpose, since it stays automatically accurate. Use static ip4/ip6 entries only if you have a specific reason to avoid the lookup cost and are willing to manually track the vendor's IP changes yourself.
Yes, immediately and completely for that vendor's future sends, since the receiving server will no longer see that vendor's IPs as authorized once the include is removed and DNS propagates.
No, this varies significantly by vendor. Some resolve to a single flat list of ip4/ip6 entries costing exactly 1 lookup; others nest through two or three additional includes internally, costing considerably more against your 10-lookup budget.
Yes — query the vendor's SPF include domain's TXT record directly, or use an SPF lookup tool that recursively expands includes, before adding it to your own record so you know its real lookup cost in advance.
include evaluates a target record as one mechanism among others in your own record and continues past it; redirect fully replaces the remainder of your record's evaluation with the target's, and no mechanisms after a redirect are ever evaluated.
SPF is evaluated per exact domain used in the envelope sender, so a subdomain sending mail needs its own SPF record (which can itself use include) — it doesn't automatically inherit the parent domain's record.