Search code examples
dnsspam-preventionspf

Combining multiple SPF records, how to decide what qualifier should be used?


I'm not sure what qualifier I should be using when trying to combine SPF records.

I know there are plenty of other questions on StackOverflow in regards to what combined SPF record is correct but there isn't one that I can find that explains clearly why a certain qualifier should be used when there are different qualifiers suggested by various services.

My current record looks like:

v=spf1 +a +mx +ip4:111.222.333.444 include:_spf.google.com ~all include:servers.mcsv.net ?all include:mailgun.org ~all

Google's SPF record is:

  • include:_spf.google.com ~all

Mailchimp's SPF record is:

  • include:servers.mcsv.net ?all

Mailgun's SPF record is:

  • include:mailgun.org ~all

How am I supposed to decide what qualifier to use out of +all, -all, ~all and ?all?

What one out of the following is correct?

  1. v=spf1 +a +mx +ip4:111.222.333.444 include:_spf.google.com include:servers.mcsv.net include:mailgun.org ~all
  2. v=spf1 +a +mx +ip4:111.222.333.444 include:_spf.google.com include:servers.mcsv.net include:mailgun.org ?all
  3. v=spf1 +a +mx +ip4:111.222.333.444 include:_spf.google.com include:servers.mcsv.net include:mailgun.org +all
  4. v=spf1 +a +mx +ip4:111.222.333.444 include:_spf.google.com include:servers.mcsv.net include:mailgun.org -all

MX & A

The same question goes to the use of +a and +mx do I need to include those too?

What about +'s?

Do I need to include the + before +a, +mx and +ip4

Bare in mind we send emails through Mailchimp, MailGun, Google & via the server.


Solution

  • Your current record doesn't make sense. Rules are evaluated left to right, so your default (all) mechanism should always be last.

    When you include an external SPF record, any all action it contains is effectively ignored (because it gets overridden by your own later directives).

    MailChimp's record is dumb (quelle surprise); ?all is equivalent to not having an SPF record at all, but it makes no difference in this case.

    Literal IP mechanisms are fastest because they require no DNS lookups to check, so it's considered polite to put them first.

    You don't need + in front of mechanisms as that's the default qualifier.

    The a mechanism means "allow the IP returned by the A record for this host". Similarly, mx means "allow sending from any IP that is also a mail exchanger (mail server) for this domain". If those are true, add them. I recommend putting these before any include mechanisms because they only require a single DNS lookup, and they're quite likely to be already cached by receivers anyway.

    You should never use +all; it's actively bad as it gives all sources a positive pass result, which is worse than having no SPF record. ?all is the same as not having an SPF so you shouldn't use that either.

    If you're also using DMARC, you should use ~all; if you're not, use -all. The reason for that is that SPF rules are evaluated before DMARC, and -all will cause immediate termination before DMARC gets a chance to do its thing. DMARC can then be configured to reject anything that gets a softfail, and its reporting mechanisms can do what they are meant to do.

    I'd recommend this record if you're using DMARC, and the same but -all if you're not:

    v=spf1 ip4:111.222.333.444 a mx include:_spf.google.com include:servers.mcsv.net include:mailgun.org ~all
    

    Whatever you end up with, check it on Scott Kitterman's validator.