Building an SPF Record That Actually Matches How You Send Mail

A checker can tell you whether an SPF record is well-formed, but it cannot tell you whether the record describes your real mail flow. That is the job of building the record in the first place, and it is where most SPF problems begin. A record copied from a tutorial, assembled from half-remembered provider names, or extended by adding a new include every time a new tool is adopted, will eventually disagree with reality: it will authorise servers you no longer use, omit servers you do use, or exceed the lookup limit and fail for everyone. The SPF Record Generator helps you assemble a record deliberately, mechanism by mechanism, from a list of senders you have actually identified, so the published record and the real mail flow agree.

Building a record starts not with the generator, but with an inventory. List every service that sends mail using your domain in the sender address. The obvious ones are your own mail server and your company's mail provider. The easily forgotten ones are the website contact form, the shop's order confirmations, the support ticketing system, the newsletter platform, the invoicing tool, the recruitment system, and any application that sends password resets or notifications. Each of these needs a mechanism in the record, or its mail will fail SPF checks. The inventory is the hard part, and it is worth doing properly, because a generator can only encode what you tell it; it cannot discover a sender you forgot.

How it works

A generator takes your inventory and turns it into the record string. For each sender you identify, you choose the right mechanism. A single server with a fixed address becomes an ip4 or ip6 mechanism with that address. A range of addresses, such as a provider's sending block, becomes an ip4 mechanism with a network prefix, for example a /24 range. A provider that publishes its own SPF record becomes an include mechanism pointing at that provider's domain, which is convenient but costs DNS lookups and inherits the provider's changes. Your own domain's mail servers can be covered by an mx mechanism, and your domain's web server by an a mechanism, though explicit IP mechanisms are usually clearer and cheaper in lookups than a or mx, because a and mx each cost a lookup whose result can change without warning.

Once the mechanisms are listed, the generator appends the final all mechanism. During initial testing, many administrators use ~all, soft fail, which tells receivers that unmatched senders are suspicious but should not necessarily be rejected outright, giving time to spot missing senders in reports before enforcement begins. Once the record has run cleanly for a few weeks and the missing senders have been added, the record should move to -all, hard fail, which is the setting that actually protects the domain, because soft fail leaves receivers free to deliver forged mail anyway. The generator also counts the DNS lookups the record would cause, which is essential, because a record that looks tidy can still exceed the ten-lookup limit once its includes are expanded.

Worked example

Suppose a small business sends mail from three sources, using sample values for illustration. Its own mail server is a single address, 203.0.113.10. Its shop sends order mail from the range 203.0.113.0/24. Its newsletter platform asks customers to include _spf.newsletter-example.com. Assembling those in order, with the version declaration first and a strict final mechanism, gives:

v=spf1 ip4:203.0.113.10 ip4:203.0.113.0/24 include:_spf.newsletter-example.com -all

The lookup count is 1, for the single include, well inside the limit. Note that the first ip4 mechanism is redundant, because the address 203.0.113.10 already falls inside the /24 range, and a careful builder would drop it, leaving a shorter record:

v=spf1 ip4:203.0.113.0/24 include:_spf.newsletter-example.com -all

Now suppose the business adds two more platforms, each of which includes several domains of its own, and the total lookup count rises to 12. The record is now invalid in practice, because receivers stop evaluating after ten lookups and return a permanent error. The remedy is flattening: ask one platform for its stable sending addresses and list them directly as ip4 mechanisms, which cost no lookups, bringing the count back under ten. Flattening trades automatic updates for control, since a platform that changes its addresses would then need a record update, so it is worth doing only where the provider's addresses are stable and documented, and worth recording in a note so the next administrator knows why the record looks the way it does.

Mistakes to avoid

The first mistake is generating a record without an inventory, which guarantees omissions. Walk through every system that sends mail, including the ones nobody thinks of as mail systems, such as monitoring alerts and form notifications, before generating anything. The second mistake is stacking includes without counting lookups. Each include is a promise to pay for another domain's lookups too, and a provider that adds an include of its own can push your record over the limit without you changing anything. Count lookups at generation time and re-count whenever a provider is added. The third mistake is leaving the record at ~all permanently. Soft fail is a testing stage, not a destination, and a domain that never moves to -all is not really protected, because receivers may still deliver forged mail that soft-fails.

The fourth mistake is publishing two SPF records, which happens when a new generated record is added alongside the old one instead of replacing it. A domain must have exactly one SPF record, so generation must end with replacing the old record, not appending to it. The fifth mistake is generating a record for the wrong domain, such as the bare domain when mail is sent from a subdomain, or vice versa. SPF is checked against the domain in the sender address, so a record on example.com does not cover mail sent from mail.example.com unless that subdomain has its own record or the sending domain matches. Finally, the handling rule: a generated SPF record is public data, but your DNS credentials are not. Never paste provider logins or API tokens into a generator, and publish the record through your provider's own interface.

Putting it into practice

Make SPF generation a checklist item whenever a mail-sending service is adopted or retired: inventory, generate, count lookups, test with ~all if the service is new, monitor reports for missing senders, then move to -all. Keep a short note, outside the record itself, listing which mechanism belongs to which service and why, because the record string alone does not explain itself to the next person who edits it. For neighbouring checks, the SPF Checker verifies a pasted record's format and lookup count, and the DMARC Checker covers the policy that decides what receivers do with SPF failures. For background reading, the related guide explains how SPF, DKIM, and DMARC fit together, which is the context in which any generated record should be judged.

Key points

  • Build an SPF record from a complete inventory of real senders, not from a tutorial
  • Prefer explicit IP mechanisms where addresses are stable, and count every include toward the ten-lookup limit
  • Start new records at soft fail, then move to hard fail once reports show no missing senders
  • A domain must have exactly one SPF record, on the domain that actually sends the mail