Back to blog
Threat Intel
Phishing Forensics

SPF Softfail (~all) vs. Hardfail (-all): A DMARC Operator's Calculus

A softfail is not a 'safer' SPF record; it's an ambiguous signal that undermines your DMARC enforcement and aids attackers.

MailSleuth Research
Email Security Team
May 28, 20269 min read
An illustration comparing SPF softfail and hardfail using two doors. One is ajar with a caution tag; the other is locked

You're staring at a DMARC aggregate report. A sea of red `fail` tags under the SPF column, yet many of those same emails show a DMARC `pass`. The culprit is often a familiar, misunderstood character: the SPF softfail. It's the `~all` at the end of a sender's policy, a mechanism that feels safer but, in reality, injects fatal ambiguity into your mail authentication stack.

The debate between `~all` (softfail) and `-all` (hardfail) isn't academic. It's a fundamental choice about how you want receiving mail servers to interpret messages that don't originate from your authorized infrastructure. One is a suggestion, the other is an instruction. For anyone serious about using DMARC to block spoofing, understanding this difference isn't just best practice—it's the entire game.

Let’s dismantle the common wisdom. A softfail isn’t a training wheel; it's a permanent state of indecision that attackers can and do exploit. We'll break down the operational calculus for choosing the right mechanism and when to make the switch.

How Mail Servers Interpret `~all` vs. `-all`

At its core, the Sender Policy Framework, defined in RFC 7208, is a way for a domain owner to publish a list of authorized sending IP addresses in DNS. The `all` mechanism at the end of the record dictates the default policy for any IP not on that list. This is where the choice between `~` and `-` becomes critical.

The Softfail (`~all`): A Suggestion of Doubt

A `~all` qualifier tells the receiving mail server, "This sender is probably not authorized. You should accept the message, but maybe subject it to extra scrutiny." The RFC calls this a 'softfail' result. Operationally, this means the message will likely not be rejected outright based on the SPF check alone. Instead, the receiver's mail transfer agent (MTA) might increase the message's spam score or place it in the junk folder. It's a weak signal. The MTA is left to make its own decision, weighing the softfail against other factors like sender reputation, content analysis, and user history.

The Hardfail (`-all`): An Explicit Command

Conversely, a `-all` qualifier is a direct instruction. It says, "If the sending IP is not on my list, the message is fraudulent. Reject it." This is a 'fail' result, often called a hardfail. Modern mail receivers treat this signal with significant weight. While some might still deliver the message to spam depending on their internal policies, many will reject the connection at the SMTP level or silently discard the message. The ambiguity is gone. You, the domain owner, have made a definitive statement about the legitimacy of the source.

The key takeaway is that `~all` outsources the final decision to the receiver, while `-all` takes a firm stance. For a SOC analyst, this difference is night and day. A softfail creates noise and alerts that require correlation with other data points. A hardfail creates a clean, binary event: the mail was either from a valid source or it was blocked. End of story.

The DMARC Alignment Trap

Here is the single most misunderstood concept in the `~all` vs. `-all` discussion: for the purposes of a DMARC evaluation, SPF softfail and SPF hardfail are treated exactly the same. Both are considered a `fail`.

DMARC, defined in RFC 7489, doesn't care about the subtle distinction between softfail and hardfail. It asks a simple, binary question: did the SPF check produce a `pass` result? If the answer is anything else—`fail`, `softfail`, `neutral`, `temperror`, `permerror`—DMARC considers the SPF portion of its check to have failed. What DMARC *really* cares about is 'identifier alignment.' This means the domain in the `From:` header (what the user sees) must match the domain found during the SPF or DKIM check.

Authentication-Results: mx.google.com;
spf=softfail (google.com: domain of transitioning user@example.com does not designate 203.0.113.10 as permitted sender) smtp.mailfrom=user@example.com;
dkim=pass header.i=@sendgriddomain.com;
dmarc=pass (p=NONE sp=NONE) header.from=example.com

Look at the example header above. SPF produced a `softfail`. From DMARC's perspective, that's a failure. However, DKIM passed, and its domain (`sendgriddomain.com`) was presumably aligned with the `From:` header domain (`example.com`) or was trusted. Because at least one of the two methods (SPF or DKIM) passed and was aligned, the overall DMARC result is `pass`. This is why you can't rely on your SPF policy alone to get your mail delivered or blocked. DMARC is the policy engine that looks at both SPF and DKIM together.

So if DMARC treats `~all` and `-all` the same, why choose one over the other? Because the receiver's MTA can act on the SPF result *before* the DMARC evaluation is complete. A `-all` can get an email rejected at the earliest stage, preventing it from ever being processed further. A `~all` lets it in the door, forcing the rest of your security stack to deal with it.

The Migration Scenario: Is Softfail a 'Safer' Staging Tool?

There's one legitimate, tactical use case for an SPF softfail: during a complex mail service migration or an initial DMARC rollout. Imagine you're moving from a legacy on-premise Exchange server to Google Workspace while also onboarding a new marketing platform like Mailchimp and a new support desk like Zendesk.

Your SPF record is about to get complicated. You’ll have `include:` mechanisms for Google, Mailchimp, and Zendesk, plus any other third-party services that send mail on your behalf. The chances of missing a sending service are high. Shadow IT is real; that one department using an obscure invoicing tool that sends from their own servers is a classic example.

Using `~all` for Discovery

In this scenario, using `~all` combined with a DMARC policy of `p=none` is a powerful discovery tool. When that forgotten invoicing server sends an email, its IP won't be in your SPF record. The receiving server will see the `~all` and register a `softfail`. Because your DMARC policy is in monitoring mode (`p=none`), the receiver won't reject the email. It will, however, send a DMARC aggregate report back to you, detailing the IP address, the SPF failure, and the mail volume. Business isn't interrupted, but you gain critical visibility into your mail streams. The softfail prevented an outright rejection, turning a potential service outage into actionable intelligence.

The Risk of Using `-all` Too Early

If you had started with `-all` in the same scenario, emails from that invoicing server would have been hard-rejected. The finance department calls you, furious that invoices aren't being delivered. You have no immediate data on why, because rejection often happens at the SMTP level, and DMARC failure reports might not even be generated. You're now scrambling to identify the sending IP from angry user reports instead of calmly analyzing DMARC data.

So yes, `~all` is a useful, temporary state. It's a scaffolding you erect while you build out your authoritative list of senders. The mistake is leaving the scaffolding up after the building is complete.

The Final State: Hardfail for Unambiguous Security

Once your migration is complete and your DMARC reports show a consistently high percentage of passing, aligned mail, it's time to remove the ambiguity. Move to an SPF hardfail (`-all`) and advance your DMARC policy to `p=quarantine` or, ultimately, `p=reject`.

Why? Because attackers thrive on ambiguity. A `~all` policy is an open invitation for them to test a receiver's defenses. A threat actor attempting a Business Email Compromise (BEC) attack by spoofing your CEO's address wants their email to land in the inbox. If you have a softfail, they're betting that the target's mail gateway won't weigh the softfail heavily enough to block the message. They only need to be right once.

A `-all` policy slams that door shut. It provides a clear, machine-readable signal of non-authorization. When combined with DMARC at enforcement (`p=reject`), you're instructing the world: "Any email claiming to be from my domain that fails authentication is fraudulent. Do not deliver it." This dramatically shrinks the attack surface for direct domain spoofing. It doesn't solve lookalike domains or compromised accounts, but it perfectly addresses the threat of an external attacker forging an email from your exact domain.

From an incident response perspective, attribution is faster. With `-all`, if you see a report of a spoofed email, you can quickly determine if it was a configuration error (e.g., a new service wasn't added to SPF) or if the receiving MTA ignored your DMARC policy—a far less common scenario with major providers. The investigation is streamlined because the policy was clear.

Auditing Your Effective Policy in a World of `include`

Your SPF record is rarely a simple, one-line entry. It’s a chain of dependencies linked by `include:` and `redirect=` mechanisms. Your record might end in `~all`, but one of the included records from a vendor could contain a `-all` or another `~all`. The final, effective policy is determined by the first `all` mechanism encountered during the evaluation. This can lead to nasty surprises.

Furthermore, RFC 7208 imposes a hard limit of 10 DNS lookups to fully resolve an SPF record. It's surprisingly easy to exceed this limit when you have multiple `include` statements, especially nested ones where a vendor's record includes other vendors' records. If you exceed 10 lookups, the SPF check results in a `permerror`, which DMARC treats as a `fail`. This breaks your mail authentication just as effectively as a misconfigured IP.

Never assume you know what your effective SPF policy is. Use an online SPF checker to validate your record. These tools recursively resolve all `include` and `redirect` statements, flatten the entire chain into a single list of IP ranges, and show you the final effective policy—including whether you passed the 10-lookup test. This is not an optional step; it is essential hygiene for any domain administrator.

The takeaway

The SPF `~all` is not a long-term security control. It's a temporary, tactical tool for discovery during a DMARC implementation. You use it to find your legitimate senders without breaking business continuity. Once you have that visibility, your objective should always be to move to `-all` in concert with a DMARC enforcement policy.

Making the switch from `~all` to `-all` is the moment you stop suggesting what's legitimate and start declaring what isn't. It's the point where you take full ownership of your domain's reputation and provide the unambiguous signal that mail gateways need to block phishing and spoofing attacks. Don't leave your door half-open; once you know who has a key, lock it. Analyzing your DMARC aggregate and forensic reports in a platform like MailSleuth.AI will give you the confidence to know precisely when to turn that deadbolt.

#spf#dmarc#email-security#spoofing#dns
MailSleuth Research
Email Security Team

We dissect phishing campaigns and email infrastructure so you don't have to.