DEV Community

Cover image for SPF redirect vs include: when to use each (and 5 mistakes to avoid)
Petr Michal
Petr Michal

Posted on

SPF redirect vs include: when to use each (and 5 mistakes to avoid)

SPF redirect= vs include:: when to use each

SPF has two features that are easy to confuse:

include:
redirect=
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Use redirect= 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
Enter fullscreen mode Exit fullscreen mode

It may look like this means:

  1. allow Google,
  2. reject anything else,
  3. then try the redirected policy.

That is not how SPF works.

The all mechanism always matches.

So when evaluation reaches:

-all
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

If your current domain owns the final policy:

v=spf1 include:_spf.google.com -all
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

And your domain publishes:

v=spf1 include:_spf.provider.com ?all
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

This can be valid, but its meaning is different.

SPF first evaluates:

ip4:198.51.100.20
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

And then:

_spf.company.example:
v=spf1 include:_spf.google.com include:spf.mailvendor.example -all
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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=
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

redirect=

The current domain delegates its remaining SPF policy to another domain.

v=spf1 redirect=_spf.company.example
Enter fullscreen mode Exit fullscreen mode

So the shortest useful summary is:

include:  -> extend my policy
redirect= -> delegate my policy
Enter fullscreen mode Exit fullscreen mode

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)