SPF validator for an IP or CIDR range

Is this IP address, or this whole range, allowed to send mail for the domain?

Fail

1 problem needs fixing for 203.0.113.25.

1 fail · 0 warning · 0 pass · 0 note

  1. Fail

    F1203.0.113.25 is not authorised (SPF fail)

    The record explicitly rejects this sender (-all).

    FixAdd the sending service's include: or the address with ip4:/ip6:, keeping the total under 10 DNS lookups.

    Why this matters and how to fix it →

Result

AddressesCountResultDecided by
203.0.113.251failexample.com → -all

Evaluation tree

  • example.com

    v=spf1 -all

0 of 10 DNS lookups used · 0 void lookups

Raw data
{
  "domain": "example.com",
  "network": "203.0.113.25",
  "isRange": false,
  "total": 1,
  "passed": 0,
  "verdict": "not_authorized",
  "overall": "fail",
  "byResult": {
    "fail": 1
  },
  "rows": [
    {
      "range": "203.0.113.25",
      "count": "1",
      "result": "fail",
      "trail": [
        "example.com",
        "-all"
      ],
      "detail": ""
    }
  ],
  "tree": [
    {
      "depth": 0,
      "domain": "example.com",
      "record": "v=spf1 -all",
      "status": "ok",
      "lookups": 0
    }
  ],
  "lookups": 0,
  "voids": 0
}

How this check works

The validator implements the check_host() algorithm from RFC 7208. It fetches the domain's SPF record, walks its mechanisms in order, follows include: and redirect=, resolves a and mx targets, expands macros, and enforces the 10-lookup and 2-void-lookup limits. The envelope sender is assumed to be postmaster@ the domain; that only matters for records that use sender macros.

Whole ranges in one pass

Enter a CIDR range such as 198.51.100.0/24 and the validator evaluates every address in it at once. Each mechanism claims the part of the range it matches, so the result is exact for every address, not a sample. Terms whose result depends on the individual address (ptr, or macros such as %{i}) are evaluated address by address for ranges of up to 256 addresses, and marked indeterminate for larger ones.

How to read the results

  • Authorised: every address gets SPF pass.
  • Partially authorised: some sub-ranges pass and others don't. The table shows each sub-range, its result, and the chain of terms that decided it, e.g. example.com → include:_spf.vendor.example → ip4:198.51.100.0/25.
  • Not authorised: no address passes. The result tells you why: fail (explicitly rejected by -all), softfail (~all), neutral, none (no record), permerror (broken record) or temperror (DNS failure).
  • Records evaluated lists every SPF record fetched, indented by include depth.

Typical uses

  • Onboarding a mail relay or a new ESP: confirm its published range is fully covered before switching traffic.
  • Explaining a softfail in a bounce: enter the sending IP from the headers and see which term it reached.
  • Auditing after a cleanup: check that removing an include didn't drop a range you still use.

If evaluation stops with a permerror at the lookup limit, see fixing "SPF too many DNS lookups". For the anatomy of a record, see SPF explained.

Updated 26 October 2026

Related checks

Guides for this check

FAQ

What's the difference between fail and softfail?

The -all qualifier (fail) asks receivers to reject unauthorized mail. The ~all qualifier (softfail) asks them to accept it but mark it as suspicious. Under DMARC, both typically count as an SPF failure.

Which sender address is used?

The evaluation uses postmaster@<your-domain> as the envelope sender. This only matters for records that use sender macros like %{s} or %{l}.

How large a range can I test?

The whole range is evaluated as a set of blocks, so a /16 or an IPv6 /48 works in one pass. Only terms that depend on the individual address, such as ptr, fall back to evaluating addresses one at a time, up to 256 of them.