SPF permerror Under p=reject: The CIDR Bug Your Validator Won't Catch

Binary breakdown of 135.84.68.123/28 showing the /28 network's base IP is 135.84.68.112, not 135.84.68.123, illustrating why the host address is invalid as a CIDR network specifier in SPF records

Your SPF record validates green at most public validators. Your DMARC is at p=reject. And somehow, legitimate mail from one of your own IPs is bouncing.

The bug isn't in your DMARC. It's a single digit in your SPF that almost every validator says is fine.

A logistics company we audited recently had a textbook DMARC enforcement setup. Policy at p=reject, aggregate reports flowing to a monitored inbox, failure reports configured, all the right ESP integrations included. They had done the work. On paper, everything was correct.

Their SPF record looked like this:

v=spf1 ip4:135.84.68.123/28 mx include:mail.zendesk.com include:servers.mcsv.net include:_spf.google.com include:mg-spf.greenhouse.io include:_spf.ultipro.com include:43850348.spf07.hubspotemail.net ~all

Terminal output of dig +short TXT showing an SPF record with the malformed mechanism ip4:135.84.68.123/28 highlighted
A live dig query returning the SPF record as published in DNS. The highlighted mechanism ip4:135.84.68.123/28 is the bug.

Run that through most public SPF validators and you get a green check. Syntax is clean. No more than ten DNS lookups. No deprecated mechanisms. No conflicting records. Every include resolves. The ~all softfail is correctly placed at the end. If you're operating from a checklist, this record passes — at most validators. URIports is the only mainstream tool we've found that catches this specific bug, and it does so explicitly, flagging that the IP address is not aligned with its CIDR network mask. Kitterman, MXToolbox, EasyDMARC, and dmarcian's inspector all return clean results on the same record.

dmarcian SPF inspector returning a green pass on an SPF record containing the malformed CIDR mechanism ip4:135.84.68.123/28
dmarcian's SPF inspector returns "Great job! You have a valid SPF record" on a record with a malformed CIDR mechanism. The misaligned network address goes unflagged.

The problem is the first mechanism: ip4:135.84.68.123/28.

What /28 Actually Covers

CIDR notation isn't a range you can wave at. It's a precise mathematical specification of a network. The /28 says "the first 28 bits of this 32-bit address identify the network, and the last 4 bits identify the host within that network." Four bits gives you 16 possible values, so a /28 covers exactly 16 IP addresses.

Those 16 addresses aren't arbitrary. They're aligned to a 16-address boundary. For the network containing 135.84.68.123, the math works out like this. The address in binary ends in 0111 1011, which is 123 in decimal. Masking the last 4 bits to zero gives 0111 0000, which is 112. So the network address is 135.84.68.112, the broadcast address is 135.84.68.127, and valid host addresses are 135.84.68.113 through 135.84.68.126.

CIDR calculator showing the /28 network containing 135.84.68.123 spans from 135.84.68.112 (First IP) to 135.84.68.127 (Last IP) for a total of 16 hosts
The /28 network containing .123 actually spans .112 through .127. The network address is .112 — not .123. Writing 135.84.68.123/28 puts a host address where a network address belongs.

135.84.68.123 is a valid host address inside that network. It is not a valid network address. Writing 135.84.68.123/28 is mathematically meaningless — it's the IP equivalent of describing a city block by referencing a single house number on it without saying which block you meant.

RFC 4632, which defines CIDR notation, is unambiguous: the prefix length describes a network, and the address preceding the slash must be the network address. Anything else is malformed.

What the company meant to write was one of two things. If they wanted to authorize the entire 16-address block, the correct record is ip4:135.84.68.112/28. If they wanted to authorize only the single IP at .123, the correct record drops the CIDR entirely and just writes ip4:135.84.68.123. SPF treats a bare IPv4 address as an implicit /32, which authorizes exactly that address and nothing else.

What they actually have is neither. It's an ambiguous specification that asks every receiving mail server to make a judgment call about what the sender meant. And different receivers make that judgment differently.

Why the Same Record Gets Different Answers from Different Receivers

RFC 7208 — the SPF specification — says that any syntactic error in an SPF record must produce a permerror result. A receiver encountering ip4:135.84.68.123/28 should reject the SPF evaluation as malformed, return permerror, and treat that as a hard failure for DMARC purposes.

That's the spec. Practice is messier.

Most major receivers don't strictly enforce CIDR network-address validation. Some normalize the address by masking the host bits and treat 135.84.68.123/28 as if the sender had written 135.84.68.112/28 — silently expanding the authorization to the full 16-address block. Others reject the mechanism but continue evaluating the rest of the record, falling through to the ~all softfail. A smaller number return permerror and stop.

The result is that the same record produces different SPF results at different mailbox providers, often within the same hour, often from the same sending IP. We've seen Microsoft 365 return temperror on malformed SPF mechanics that other receivers swallow without comment — and Microsoft's own response in support tickets has been, in one case we encountered, that the temperror was "within acceptable tolerance." Acceptable to whom is left as an exercise for the sender.

Microsoft's behavior is the most consequential here because Microsoft handles a substantial share of B2B mail and is the most aggressive about returning ambiguous SPF results. Research published in the last 18 months across roughly two billion DMARC-evaluated messages shows Microsoft generating SPF and DKIM permerror and temperror results at rates several thousand percent higher than every other major receiver combined. The cause traces back to internal Windows DNS resolver behavior in Microsoft's spam-filtering infrastructure, which has a separate set of bugs around DNS retries and cache handling. When you stack that on top of a malformed SPF mechanism, you get a record that passes at Gmail, fails at Microsoft, and passes-then-fails-then-passes-again over the course of a week depending on what their resolvers happen to be doing.

Gmail tends to be more permissive. Their evaluator appears to normalize CIDR mechanisms by masking host bits, so 135.84.68.123/28 gets interpreted as 135.84.68.112/28 and mail from the sending IP authenticates correctly. Yahoo's behavior is closer to the spec — they're more likely to return a hard permerror — but with significantly less consistency than the documentation would suggest.

None of this is documented anywhere a sender can find it. The behavior is empirical. You discover it by enforcing p=reject and watching legitimate mail bounce at one specific provider.

Why Most Validators Don't Catch This

Every major SPF validator parses the record syntactically. They check that mechanisms are well-formed, that prefix lengths are between 0 and 32 for IPv4, that the DNS lookup count is under 10, that the all mechanism appears last and only once. What most of them do not check is whether the address preceding the slash is actually the network address for that prefix length.

This is a structural gap. A CIDR mechanism with a host address instead of a network address is syntactically legal — it has the right number of dots, the right number of bits, a valid prefix length — but semantically meaningless. Validating for semantic correctness requires the validator to do the bitmask math and compare the result to the address as written. URIports does this and flags the misalignment with a specific error message and a suggested correction. Most other validators don't. Kitterman, MXToolbox, EasyDMARC, and dmarcian's inspector will return clean results on 135.84.68.123/28. The user sees a passing record at the validator they happen to use and concludes the SPF is fine.

URIports SPF policy tool flagging that the IP address 135.84.68.123/28 is not aligned with its CIDR network mask, with a suggested correction using 135.84.68.112/28
URIports is the only mainstream SPF validator we've found that catches this class of bug. The error message is specific, and the tool even suggests the corrected record.

The DNS provider doesn't catch it either — most DNS hosting platforms accept any string in a TXT record without parsing the SPF semantics. Cloudflare, Route 53, Namecheap, GoDaddy, all of them will publish whatever you type.

The result is a record that looks correct at every checkpoint between the admin and the receiving mail server, but fails inconsistently at the only checkpoint that matters.

Other SPF Bugs That Live in the Same Failure Mode

The CIDR network-address bug is the most subtle example of a broader pattern: SPF records that are syntactically valid but mechanically broken in ways that receivers handle inconsistently. Under p=none, none of these cause visible problems. Under p=reject, they cause delivery failures that look random.

Exceeding the 10-lookup limit. RFC 7208 caps the number of DNS lookups an SPF evaluation can perform at 10. Every include, a, mx, exists, and redirect mechanism counts. Nested includes count their own lookups against the same limit. We routinely see records that pass 10 lookups because the organization added a new ESP, and the ESP's include resolves to a chain of nested includes that pushes the total to 12 or 14. The result is a permerror at every spec-compliant receiver — but receivers like Microsoft sometimes return temperror and pass the message through anyway, which hides the problem until a more strict receiver rejects.

ptr mechanisms. The ptr mechanism was deprecated in RFC 7208 in 2014. It's slow, it's unreliable, and most receivers refuse to evaluate it. It is still present in production SPF records across thousands of domains, usually as a vestige of a configuration written before deprecation. A record with a ptr mechanism will sometimes pass and sometimes return permerror depending on whether the receiver bothers to evaluate it. Under p=reject, the variance is the problem.

Mechanisms after all. The all mechanism is supposed to be the last token in the record. Anything after it is unreachable by the SPF evaluator and is, per spec, a syntax error. We see records — usually the result of someone appending an include without removing the previous ~all — where a new include sits after the original all. Strict receivers return permerror. Lenient receivers reorder, ignore, or fall through. Same record, three different outcomes.

+all. This one isn't subtle. +all is a positive-match wildcard that explicitly authorizes every IP address on the internet to send mail for the domain. It exists because the SPF grammar allows it, but its only legitimate use is in test environments. We find it in production SPF records more often than anyone would expect, usually because someone copy-pasted an example from a forum thread and didn't read what they were committing. Under p=reject, +all doesn't cause bounces — it causes the opposite problem, which is that every spoofed message also passes SPF and aligns under DMARC. The domain is technically protected by the policy and substantively defenseless.

Each of these bugs has the same structural property as the CIDR network-address error: most validators don't reliably catch them, DNS providers don't enforce against them, and receivers disagree about how to handle them.

Why p=reject Changes Everything

Under p=none, a malformed SPF record is invisible. Mail still delivers — the policy explicitly tells receivers to take no action on authentication failures. The malformed mechanism shows up as a permerror in the aggregate reports, but the reports are XML files that nobody reads unless they've already plugged them into a monitoring tool, and most domains running p=none haven't.

Under p=quarantine, the same record routes failing messages to the spam folder. Users notice. They complain. The problem surfaces within days, usually via a customer or internal team reporting that emails are landing in junk. There's pain, but it's recoverable — you fix the record, the messages start flowing to the inbox again, and the only damage is a few days of degraded engagement.

Under p=reject, the failure mode flips. Messages that fail DMARC are rejected at the SMTP layer, before they reach the recipient's mailbox. The sender gets a bounce. The recipient never knows the message existed. And because SPF evaluation is inconsistent across receivers, the bounces are intermittent — mail to Gmail gets through, mail to Microsoft bounces, mail to Yahoo bounces sometimes and passes other times. From the sender's perspective, the symptom is "our customers stopped responding," not "our SPF is malformed." The diagnostic chain that leads from the symptom to the cause is several steps long and usually requires someone with deliverability experience to walk it.

This is the failure mode that catches teams off guard. They executed the DMARC rollout correctly. They moved from p=none to p=quarantine with pct ramping. They monitored for weeks. Nothing failed. Then they moved to p=reject — and within 24 hours, a portion of their B2B mail to Microsoft tenants started bouncing for reasons nobody could trace.

The cause, almost always, is that the SPF passed at every receiver during the quarantine phase because quarantine doesn't reject on permerror — it routes to spam, and the messages were almost always still being read because users were checking their junk folder. The transition to reject changed the behavior at the receivers that strictly enforce permerror, and a record that had been "working" for years suddenly stopped.

Already at p=reject and worried something's bouncing?

Let us review your SPF, DMARC, and aggregate reports.

Book a 30-Minute Call

How to Audit Your SPF Before Enforcement

The pre-enforcement SPF audit is the single highest-leverage step a team can take before flipping the DMARC policy. Most of the work takes an hour. The cost of skipping it can be weeks of degraded B2B deliverability.

Start by pulling your current SPF record with dig +short TXT example.com and inspect every mechanism by hand. Don't trust the validator — verify each piece independently. For every ip4 mechanism with a CIDR prefix, run the bitmask math: take the address, convert the last octet to binary, mask the host bits according to the prefix length, and confirm the result matches the address as written. If you're authorizing a single IP, drop the CIDR entirely. If you're authorizing a block, use the network address. URIports is worth running the record through specifically because it catches this class of bug; it's not a replacement for manual inspection, but it's a useful second pass.

For every include, resolve it. Count the lookups in your record and in each nested include. The total across the entire evaluation chain must be 10 or fewer. If you're at 9 or 10, you have no headroom for the next ESP someone adds, and you should consolidate or remove unused mechanisms now.

Check that no mechanism appears after all. Check that all appears exactly once. Check that you're not using ptr. Check that the qualifier on all is ~ or -, not +.

Once the record looks clean structurally, pull two weeks of DMARC aggregate reports and look for specific signals. SPF results other than pass or none are flags — permerror, temperror, softfail, and fail all warrant investigation. A receiver returning permerror for a specific sending IP is telling you that something in your record is malformed in their evaluator. A receiver returning temperror is telling you their DNS resolution failed, which on a single occasion is meaningless but on a recurring pattern indicates a record that's marginally broken in a way their infrastructure tolerates inconsistently.

Pay particular attention to results from Microsoft. Microsoft's higher rate of permerror and temperror across the industry means that what looks like noise at other receivers often surfaces as a clear signal in Microsoft's reports. If you see a Microsoft IP consistently returning permerror against your domain, you have a record problem, not a Microsoft problem.

The last step is to test the record under conditions that approximate the post-enforcement environment. Send test messages from each of your authorized sending sources to mailboxes at Gmail, Microsoft 365, Yahoo, and at least one corporate domain running its own filter. Inspect the Authentication-Results header on the delivered message. If any receiver returns a result other than spf=pass, you have a problem to resolve before moving to p=reject.

The validators have their place. They catch the obvious mistakes — missing version tags, malformed syntax, lookup overruns. What most of them don't catch is the class of bug that lives in the gap between "syntactically valid" and "mechanically correct," and that's the class of bug that breaks mail under enforcement.

The Pre-Enforcement Checklist

Before flipping DMARC to p=reject, every SPF record in your domain inventory should pass the following:

Every ip4 and ip6 mechanism with a CIDR prefix uses the actual network address for that prefix length. Single-IP authorizations have no CIDR suffix. The total DNS lookup count across all includes and nested includes is at or below 10. No deprecated mechanisms (ptr) are present. The all mechanism appears exactly once and is the final token in the record. The qualifier on all is ~ or -. Aggregate reports for the past 14 days show 100% spf=pass from every legitimate sending source, with no permerror or recurring temperror results from any major receiver. Manual test sends to Gmail, Microsoft 365, Yahoo, and a corporate domain all return spf=pass in the Authentication-Results header.

If any of these don't hold, fix the record first. The cost of fixing is an hour. The cost of not fixing is mail that bounces inconsistently across receivers for weeks before someone traces it back to the SPF.

At SH Consulting, we audit SPF records before clients move to DMARC enforcement, specifically to catch the mechanical bugs that validators miss. If you're approaching p=reject and want a second set of eyes on the record before you flip the switch, book a call.

Get the free Email Deliverability Guide

15 rules for reaching the inbox. Used by 450+ organizations.

Download the Guide