SPF redirect= vs include:: when to use each
SPF has two features that are easy to confuse:
include:
redirect=
Both can cause another SPF policy to be evaluated.
But they solve different problems.
A useful mental model is:
include: -> add another sender policy to your own
redirect= -> delegate the final SPF decision
That difference sounds small, but it changes how the record behaves.
If you only remember one thing from this article, remember this:
Use
include:when another service is one part of your SPF policy.
Useredirect=when another domain should own the remaining SPF policy.
Let's look at five mistakes that often appear in real SPF records.
1. Combining -all and redirect=
Consider this record:
v=spf1 include:_spf.google.com -all redirect=_spf.example.com
It may look like this means:
- allow Google,
- reject anything else,
- then try the redirected policy.
That is not how SPF works.
The all mechanism always matches.
So when evaluation reaches:
-all
SPF already has a result: Fail.
The redirect= modifier will not be used.
This is true even if you move it earlier:
v=spf1 redirect=_spf.example.com -all
redirect= is a modifier, not a normal left-to-right mechanism.
According to RFC 7208, when an SPF record contains an all mechanism, the redirect modifier is ignored.
Better patterns
If another domain should define the final SPF policy:
v=spf1 redirect=_spf.example.com
If your current domain owns the final policy:
v=spf1 include:_spf.google.com -all
I wrote about this specific trap in more detail in Why -all can make redirect= useless.
2. Thinking include: imports the other SPF record
This is another common misunderstanding:
v=spf1 include:_spf.provider.com -all
include: does not simply copy the referenced SPF record into your own.
Instead, SPF evaluates the referenced policy and asks:
Does this external policy return Pass for the current sender?
If yes, the include: mechanism matches.
If not, evaluation continues in the parent record.
Suppose the provider publishes:
v=spf1 ip4:192.0.2.10 -all
And your domain publishes:
v=spf1 include:_spf.provider.com ?all
If the sender uses 192.0.2.10, the include can match.
But if the provider's policy reaches -all, that does not automatically make the parent SPF record fail.
The parent record continues to:
?all
So the final result is controlled by the parent policy.
When include: is the right choice
Use include: when a third-party service should be one authorized sender among several:
v=spf1 ip4:198.51.100.20 include:_spf.provider.com -all
Here:
- your own IP is authorized,
- the provider's authorized infrastructure is also allowed,
- your domain still owns the final
-all.
3. Using redirect= where include: was intended
Now consider:
v=spf1 ip4:198.51.100.20 redirect=_spf.provider.com
This can be valid, but its meaning is different.
SPF first evaluates:
ip4:198.51.100.20
If that matches, the result is Pass.
If it does not match and no other mechanism returns a result, SPF evaluates the redirected policy.
That means the provider now effectively owns the remaining decision.
This is useful for centralized SPF management.
For example:
example.com:
v=spf1 redirect=_spf.company.example
example.net:
v=spf1 redirect=_spf.company.example
example.org:
v=spf1 redirect=_spf.company.example
And then:
_spf.company.example:
v=spf1 include:_spf.google.com include:spf.mailvendor.example -all
Now multiple domains share one central SPF policy.
Ask one question
Who should own the final decision?
If the answer is this domain, use include:.
If the answer is the referenced domain, redirect= may be the right choice.
4. Redirecting to a broken or missing SPF target
This record is only as reliable as its target:
v=spf1 redirect=_spf.example.com
If _spf.example.com has no usable SPF record, the result is not a harmless fallback.
A bad redirect target can cause PermError.
That makes centralized SPF powerful, but also potentially dangerous.
One incorrect DNS change can affect every domain that depends on the central record.
Before using redirect
Check that the target:
- exists,
- publishes one valid SPF policy,
- returns the expected results,
- is not accidentally duplicated,
- is monitored when many domains depend on it.
If you manage dozens of domains, the redirected SPF record may be one of the most important DNS records in your email infrastructure.
5. Forgetting the 10-DNS-lookup limit
SPF limits DNS-querying terms during evaluation.
Mechanisms and modifiers that can contribute include:
include:
a
mx
exists:
redirect=
The maximum relevant DNS-querying terms is 10.
This means a simple-looking record can still be expensive:
v=spf1 include:_spf.google.com include:spf.vendor.example redirect=_spf.company.example
You cannot determine the real lookup cost by looking only at this line.
Each include: can lead to more SPF records.
The redirected policy can also contain more includes, MX lookups, A lookups, or other DNS-dependent mechanisms.
So this:
v=spf1 redirect=_spf.company.example
might look extremely simple while the actual recursive evaluation is already close to the SPF limit.
If the limit is exceeded, SPF can return PermError.
Debug the whole tree
When troubleshooting SPF, expand the full dependency chain.
Do not just count the terms in the top-level record.
include: vs redirect= in one table
| Scenario | Use |
|---|---|
| Authorize Google Workspace, Microsoft 365, Mailgun, etc. as one sender | include: |
| Combine your own IPs with a third-party sender | include: |
| Share one central SPF policy across multiple domains | redirect= |
| Delegate the remaining SPF decision to another domain | redirect= |
Keep your own final -all policy |
include: |
Use -all and then fall back to redirect |
Not possible |
A practical debugging checklist
When an SPF record behaves unexpectedly, check these in order.
1. Is there an all mechanism?
For example:
-all
~all
?all
+all
If all is present, redirect= is not your fallback.
2. Should this be include: instead?
If you only want to authorize an email provider, you probably want include:.
3. Does the redirect target have a valid SPF record?
Check the target directly.
4. How many DNS lookups happen recursively?
Follow every include and redirect.
5. Are multiple SPF policies published?
Multiple competing SPF records can make the domain invalid.
6. Is the redirect modifier duplicated?
This is broken:
v=spf1 redirect=_spf.one.example redirect=_spf.two.example
A duplicate redirect can result in PermError.
Final rule of thumb
Most SPF configurations become easier to reason about if you think in terms of ownership.
include:
The current domain owns the SPF policy.
It temporarily checks another domain to see whether the sender should be authorized.
v=spf1 ip4:192.0.2.10 include:_spf.provider.com -all
redirect=
The current domain delegates its remaining SPF policy to another domain.
v=spf1 redirect=_spf.company.example
So the shortest useful summary is:
include: -> extend my policy
redirect= -> delegate my policy
If you are debugging a real SPF record, the MXFend SPF checker can help inspect the published configuration.
For a deeper explanation of the modifier itself, including DNS lookup behavior, edge cases, and examples, see the SPF redirect modifier guide.
Top comments (0)