SPF Softfail (~all): What It Means and Whether to Use -all

`~all` is the SoftFail qualifier on the SPF record's final `all` mechanism. Per RFC 7208 §8.5, SoftFail means the domain owner believes the sending host is *probably not* authorized, but is not asserting that strongly, it is an explicit "weak" negative between Neutral (`?all`) and Fail (`-all`). A receiver that gets a SoftFail result should accept the message but MAY subject it to closer scrutiny (e.g. spam-tag it). `-all` (Fail/HardFail, §8.4) is the strong assertion that any host not listed is unauthorized, which receivers may use to reject outright. The mechanism ordering matters: `all` only takes effect for senders that didn't already match an earlier `include:`, `a`, `mx`, or `ip4/ip6` mechanism.

Why it matters

On its own, `~all` provides almost no enforcement: forged mail from unlisted IPs is typically still delivered (often just spam-scored), so it does little to stop spoofing of your domain. Switching to `-all` invites receivers to reject unauthorized mail, which is stronger anti-spoofing, but if your SPF record is incomplete, `-all` will cause legitimate mail (forwarded messages, a forgotten SaaS sender) to be rejected instead of soft-failed. The modern resolution is that the `~all` vs `-all` choice is largely subordinate to DMARC (RFC 7489): DMARC enforcement keys off whether SPF *passed and aligned*, not on your `all` qualifier, so a DMARC policy of `p=reject` gives you real anti-spoofing protection while `~all` keeps the failure mode safe. This is governed by RFC 7208: Sender Policy Framework (SPF).

Common causes

  • Provider defaults: Google Workspace and Microsoft 365 setup wizards publish `~all`, so most records inherit SoftFail without a deliberate decision.
  • Incomplete sender inventory: admins keep `~all` because they aren't certain every legitimate source (marketing platform, ticketing system, ERP, on-prem relay) is listed, and don't want `-all` to reject real mail.
  • Fear of breaking forwarding: plain forwarding rewrites the path but not the envelope sender, so the original SPF fails at the next hop; `~all` avoids hard rejections when SRS isn't in play.
  • No DMARC in place, so the admin is relying on the `all` qualifier alone for enforcement and hedges with SoftFail to avoid collateral damage.
  • Migration / transitional state: mid-move between mail providers, both old and new senders must pass, so the record is deliberately left permissive.
  • Misconception that `~all` and `-all` are functionally interchangeable, or that `~all` still 'blocks' spoofing.

How to fix SPF Softfail (~all)

  1. Decide based on DMARC, not in isolation: your real anti-spoofing enforcement should come from a DMARC record. Publish/confirm `_dmarc` and move it toward `p=quarantine` then `p=reject` once reports are clean, this makes the `~all`/`-all` distinction far less critical.
  2. Inventory every legitimate sending source using DMARC aggregate (RUA) reports over 2-4 weeks. Identify each IP/provider that sends as your domain before tightening anything.
  3. Make sure all those sources are represented in one SPF record for the domain: a single TXT record starting `v=spf1`, listing `include:`/`a`/`mx`/`ip4:`/`ip6:` mechanisms, ending in exactly one `all`. Two `v=spf1` records is a PermError.
  4. Stay within the RFC 7208 §4.6.4 limit of 10 DNS-querying mechanisms across the whole recursive expansion, audit `include:` chains (e.g. `include:_spf.google.com` alone costs ~3-4 lookups) and remove unused SaaS senders rather than stacking more includes.
  5. Once the record is verified complete and DMARC is at enforcement, change `~all` to `-all` for the strongest posture. If you cannot be certain the record is complete, it is safer to leave `~all` and rely on DMARC `p=reject` for enforcement, do NOT publish `-all` over an incomplete record.
  6. For forwarding-heavy domains, ensure forwarders use SRS (sender rewriting) and rely on DKIM (RFC 6376) + DMARC alignment so legitimate forwarded mail survives even when SPF path-checks fail.
  7. Publish the change with a low DNS TTL first, re-check DMARC reports for new failures over a week, then confirm no legitimate senders are being rejected before considering it done.

Frequently asked questions

Is ~all or -all better?

`-all` is the stronger anti-spoofing posture and is the recommended end state, but only once your SPF record demonstrably lists every legitimate sender. Until then `~all` is the safer default because a failure soft-fails instead of getting rejected. With DMARC at `p=reject`, `~all` is perfectly acceptable, since DMARC (not the SPF qualifier) provides the enforcement.

Does ~all stop people from spoofing my domain?

Largely no. SoftFail asks receivers to accept-but-scrutinize, so forged mail is usually still delivered (often just spam-scored). Real spoofing protection comes from a DMARC policy of `quarantine` or `reject` backed by aligned SPF and/or DKIM, not from the `all` qualifier by itself.

Will switching to -all break my email?

Only if a legitimate sender is missing from your SPF record, then its mail can be rejected outright instead of soft-failed. Inventory all senders via DMARC reports first; if the record is complete, `-all` will not affect legitimate mail. If in doubt, keep `~all` and enforce via DMARC.

Does the ~all vs -all choice affect whether SPF passes DMARC?

No. DMARC only checks whether SPF produced a `pass` result on an identifier aligned with the From: domain. The final-`all` qualifier only governs the *fail* side, which DMARC ignores in favor of your DMARC policy. That's why the choice is secondary once DMARC is deployed.

Related