Email authentication

SPF flattening explainer

See how many of a domain’s SPF lookups flattening would actually remove, and what it costs to keep one flattened.

Free, no accountLive check

Try

Result

The verdict and the record appear here once you press Break down the lookups.

What this is

SPF flattening means replacing an "include" with the IP ranges it happens to resolve to today, to get a record back under the ten-lookup limit. This page counts how many of a domain’s lookups could be removed that way, how many could not, and what you take on by keeping a flattened record.

RFC 7208 §4.6.4 allows a receiver ten DNS lookups to evaluate one SPF record, counted across the whole chain. Microsoft's SPF documentation lists which terms spend one: "include", "a", "mx", "exists" and the "redirect" modifier. An "ip4", "ip6" or "all" term spends none, which is the whole idea behind flattening - a provider's include is swapped for the addresses it resolves to, trading a lookup for a list.

The trade is not free. The addresses behind an include belong to the provider, who adds and retires them whenever their own capacity changes; the copy in your record does not follow. That is why this page explains the breakdown and stops there, rather than producing a flattened record for you to publish: a generated list would be accurate for an unknowable length of time and silent about when it stopped being.

How to read the result

The two numbers that matter are at the top: how many lookups come from include or redirect, and how many come from a, mx or exists. The first group is what flattening can remove. The second cannot be removed by flattening at all - those terms already name hosts of yours directly, so collapsing them just moves your own addresses into the record with the same upkeep attached.

The table lists each lookup-costing step and how deep in the chain it sits, since a provider three records down is one you have no control over at all. The tree underneath it is the same walk the SPF checker shows, so the counts on both pages always agree.

Flattening is one way back under SPF’s 10-lookup ceiling, not a fix for whatever caused the record to grow. For how SPF, DKIM and DMARC fit together, what order to fix them in, and what to do once one fails, see our guide How SPF, DKIM and DMARC work together, and what to do when one fails.

Common mistakes

What goes wrong most often, and how to tell.

  • Flattening a provider whose addresses are documented as changingMicrosoft name "include:spf.protection.outlook.com" specifically as one not to flatten, since their sending infrastructure uses dynamic addresses. A copy of those ranges breaks silently, and the symptom is a few recipients rejecting mail from one of their newer hosts.
  • Flattening a record that was never over the limitA record spending six of its ten lookups evaluates perfectly well. Flattening it swaps a working record for one that needs reviewing every quarter, with nothing gained in exchange - the lookups were not the problem.
  • Flattening instead of removing a sender nobody usesMost records over the limit got there by accumulating platforms: an old newsletter tool, a helpdesk that was replaced, a trial that ended. Deleting those costs nothing to maintain, where a flattened include costs attention forever.
  • Flattening once and treating the record as finishedMicrosoft's own guidance for anyone who does flatten is to review the flattened entries at least quarterly. A flattened record is a snapshot with an expiry date nobody writes down, and the expiry is set by somebody else.

Questions

What people ask about this tool.

  • It is rewriting an SPF record so the mechanisms that cost a DNS lookup - mostly "include" - are replaced by the ip4 and ip6 ranges they currently resolve to. The record then needs fewer of the ten lookups RFC 7208 allows, at the cost of hardcoding addresses somebody else controls.
  • Only the ones from an "include" or a "redirect", because those are the terms that open another record. An "a", "mx" or "exists" term resolves a host you already name, so flattening it only replaces your own hostname with its address and saves nothing worth the upkeep.
  • Because it would be a list of addresses that is correct the moment it is generated and silently wrong at some later date nobody can predict. A record that fails SPF for a sender you authorised is worse than one that costs a lookup too many, so this page explains the trade-off instead of producing one.
  • Microsoft's documentation says explicitly not to flatten "include:spf.protection.outlook.com" because their addresses change frequently, and warns off any cloud service with dynamic addresses. Treat a provider the same way unless they publish ranges they commit to keeping.
  • Remove senders that no longer send, which is usually at least one; move a bulk platform onto its own subdomain, which gets its own SPF record and its own budget of ten; or replace an include with the fixed ranges a provider commits to publishing, then re-check it quarterly.

Sources

Every fixed value here comes from the provider’s own documentation. These pages change, so each says the day it was last read.

Use it from the API

The same check, as one request.

Request
curl -X POST https://resellerhq.com/api/tools/spf-flattening-explainer \
  -H "Content-Type: application/json" \
  -d '{"domain":"clean.example"}'
Response
{
  "tool": "spf-flattening-explainer",
  "input": {
    "domain": "clean.example"
  },
  "result": {
    "verdict": {
      "tone": "success",
      "headline": "2 of 2 lookups for clean.example come from includes",
      "summary": "Flattening could remove 2 lookups here, and would need re-checking every time one of those providers changes an address."
    },
    "findings": [
      {
        "id": "include-lookups-counted",
        "severity": "info",
        "title": "2 of 2 lookups come from include or redirect",
        "detail": "Each of these opens a record belonging to somebody else - include:_spf.google.com, include:_netblocks.google.com - and that is the only kind of lookup flattening removes, by pasting the addresses behind it into your own record instead."
      },
      {
        "id": "flattening-goes-stale",
        "severity": "info",
        "title": "A flattened record is only right until a sender moves",
        "detail": "Flattening copies the addresses an include resolves to at one moment into your own record. The provider keeps changing them - adding a range, retiring a host - and your copy does not follow, so mail from their new servers fails SPF while your record still looks perfectly valid. Microsoft's page says to \"review and update the flattened entries at least quarterly\" if you do it."
      },
      {
        "id": "under-the-lookup-limit",
        "severity": "pass",
        "title": "Under the limit, with 8 lookups spare",
        "detail": "This record spends 2 of the 10 lookups RFC 7208 §4.6.4 allows, so it evaluates normally as published and there is nothing flattening would fix today. Flattening a record that already works buys nothing and costs the upkeep below."
      }
    ],
    "parts": [
      {
        "kind": "facts",
        "title": "Where this record spends its lookups",
        "rows": [
          [
            "Lookups used",
            "2 of 10"
          ],
          [
            "From include or redirect",
            "2 - the only ones flattening removes"
          ],
          [
            "From a, mx or exists",
            "0 - flattening does not remove these"
          ],
          [
            "Spare before PermError",
            "8"
          ]
        ]
      },
      {
        "kind": "table",
        "title": "Each lookup this record costs",
        "columns": [
          "Mechanism",
          "Where it is",
          "Worth flattening?"
        ],
        "mono": [
          0
        ],
        "rows": [
          [
            "include:_spf.google.com",
            "in clean.example's own record",
            "Yes - it opens another record"
          ],
          [
            "include:_netblocks.google.com",
            "2 records deep",
            "Yes - it opens another record"
          ]
        ],
        "note": "The ip4, ip6 and all terms are not listed: they cost no lookup, and they are what a flattened include turns into."
      },
      {
        "kind": "tree",
        "title": "The chain as walked for clean.example",
        "nodes": [
          {
            "label": "include:_spf.google.com",
            "note": "1 lookup",
            "children": [
              {
                "label": "include:_netblocks.google.com",
                "note": "1 lookup",
                "children": [
                  {
                    "label": "ip4:35.190.247.0",
                    "tone": "neutral"
                  },
                  {
                    "label": "~all",
                    "tone": "success"
                  }
                ]
              },
              {
                "label": "~all",
                "tone": "success"
              }
            ]
          },
          {
            "label": "~all",
            "tone": "success"
          }
        ],
        "note": "2 of 10 DNS lookups used, exactly as the SPF checker counts them."
      },
      {
        "kind": "record",
        "title": "Published SPF record",
        "value": "v=spf1 include:_spf.google.com ~all",
        "note": "As published today. This page never rewrites it.",
        "at": {
          "name": "clean.example",
          "type": "TXT"
        }
      }
    ],
    "lookups": [
      {
        "label": "TXT for clean.example",
        "value": "Cloudflare: 1 record"
      },
      {
        "label": "TXT for _spf.google.com",
        "value": "Cloudflare: 1 record"
      },
      {
        "label": "TXT for _netblocks.google.com",
        "value": "Cloudflare: 1 record"
      }
    ],
    "limits": [
      "This page explains the breakdown and never produces a flattened record. Flattening needs the addresses an include resolves to right now, and those drift the moment a provider changes anything - a list generated here would carry no way of telling you it had gone out of date.",
      "The counts are what is published at this minute. A provider can add a nested include to their own record tomorrow and spend another of your ten lookups without telling you, so a record this close to the limit is worth re-checking after any sending platform changes.",
      "Whether a given address behind an include is stable is the provider’s business, not something DNS can be asked. Microsoft document their own as changing frequently; most providers document nothing either way.",
      "The record’s own faults - a second SPF record beside it, a \"+all\", a missing \"all\" - are not reported here. Run the SPF checker on the same domain for those."
    ]
  }
}

This example uses a name RFC 2606 reserves for documentation, ending in .example, .test, .invalid or .localhost. None of them is a real domain, and nobody can register one.

Resell mailbox licences for the domains you just checked, under your own brand.

Get started

Company names and logos are trademarks of their owners, shown only to identify each service.