The include mechanism lets an SPF policy rely on another domain's authorisation decision. It is useful when a sending service maintains changing infrastructure. Instead of copying an address list into your record, you evaluate the provider's current policy when that include is reached.
This convenience is also a dependency. An include can change permissions as its target changes, consume the SPF lookup budget, or propagate a target error. Its behaviour is specified in RFC 7208 section 5.2.
Read include as a pass test
A normal include:service.example.net matches only if the recursively evaluated service policy returns pass for the connecting IP. The outer mechanism's default + qualifier then produces pass.
If the service returns fail, softfail or neutral, the include does not match and evaluation continues in the outer policy. If the service returns temperror or permerror, that error propagates. A target with no SPF record produces permerror for include, rather than being harmlessly ignored.
A qualifier can also precede include. For example, -include produces fail when the child returns pass. That is valid syntax but usually not the intended way to authorise a provider. Check the qualifier rather than assuming that the word include always grants access.
Worked example: preserve your own policy ending
Assuming valid syntax, one selected SPF record at each name and successful DNS retrieval, this synthetic fixture uses v=spf1 ip4:192.0.2.10 include:service.example.net -all at example.com. The service publishes v=spf1 ip4:198.51.100.9 -all.
A connection from 192.0.2.10 passes on the local mechanism. A connection from 198.51.100.9 reaches the include and passes because the child passes. A connection from 203.0.113.20 reaches the child, receives child fail, resumes the outer policy and receives fail from its final -all.
Change the outer ending to ~all and the last address receives softfail instead. The provider still decides whether include matches, but your policy determines the ordinary result when it does not. That distinction is why copying the child's whole text is not equivalent to using include.
Verify that the include belongs to your service
Obtain the exact target from current first-party product instructions. A vendor's marketing platform, transactional platform and employee mail service may have different sending paths. Do not select a plausible-looking hostname from a third-party article.
Also establish which domain the product uses in MAIL FROM. Publishing an include at example.com does not help an SPF check performed against a vendor-owned envelope domain. If you need a custom envelope, configure that capability through the product and verify it in received mail.
Maintain an owner, purpose and retirement condition for each include. A cancelled service should not retain permission indefinitely, but remove it only after checking scheduled jobs, infrequent campaigns and delegated teams.
Budget for recursive dependencies
Under RFC 7208 §4.1 and RFC 7208 §4.6.4, an include is one of the DNS-query-causing terms covered by SPF's ten-term evaluation limit. Its nested terms also count when evaluated. Several top-level includes can therefore exceed the limit even when the visible record looks short.
Use input-specific traces for legitimate sending IPs and for an unauthorised IP that traverses more of the policy. Record the target answers and evaluation time. A successful test today is not proof that a provider will never alter its dependency tree.
Replacing includes with copied IP ranges transfers maintenance responsibility to you. Do not describe that as a free simplification. You need a verified update process, IPv6 coverage and a plan for changes that occur while DNS answers are cached.
The practical takeaway
Include imports a pass decision and an operational dependency, not a promise about the visible author or message safety. Keep the target verified, the permission intentional and the recursive path within limits.
Keep the decision reproducible
Record child result and outer outcome in different columns: pass→match→outer qualifier; fail/softfail/neutral→nonmatch→continue; temperror/permerror→same error; none→permerror. For -include, child pass means outer fail. Preserve the exact target, qualifier, DNS observation and input IP with any support request. This is the RFC mapping, not live provider evidence.