SPF gives one of several results for a message, and two of them are failures of different strength. Which one you get depends on how your record ends, not on how bad the problem is.
Received-SPF: softfail (google.com: domain of transitioning bounce@example.com
does not designate 203.0.113.5 as permitted sender) client-ip=203.0.113.5;
"Transitioning" is Gmail's way of saying the domain asked for softfail. The rest of the line is the useful part: the server at 203.0.113.5 sent mail with example.com as the envelope sender, and the record for example.com does not list it.
Softfail and hardfail
The all at the end of the record answers the question "and everybody else?":
-allis fail, often called hardfail: servers not listed are not allowed to send as the domain.~allis softfail: they probably are not, but do not refuse the mail on that alone.?allis neutral: the record says nothing about them, so it protects nothing.
With a DMARC record in place, the difference matters less than it used to. DMARC asks whether SPF passed for a domain aligned with the visible sender, and a softfail and a fail are both "did not pass". What the receiver then does follows the DMARC policy. Without DMARC, receivers apply their own judgement, and some refuse on a hardfail: Gmail's 550 5.7.26 has a version that says the domain "has an SPF record with a hard fail policy (-all)".
Which to use: ~all while you are still finding every service that sends as the domain, -all once DMARC reports show nothing legitimate failing. Either is fine with DMARC at p=quarantine or p=reject.
Making the server pass
The softfail itself is the record working as written. The fix is for the server in the header to be allowed, if it should be:
- Find who owns the IP. A reverse lookup or the provider's documentation usually says which service it is.
- If it is a service you use, add its include or address to the record. Watch the ten-lookup limit while you do; the SPF checker counts it.
- If it is a forwarder, a mailing list or a security gateway relaying your message, SPF cannot pass there, by design. A DKIM signature under your domain survives a forwarder that leaves the message alone and keeps DMARC passing.
- If you do not recognise it at all, somebody may be sending as your domain. The softfail is doing its job; DMARC at
p=quarantineorp=rejectis what stops the mail.
Other results you may see
spf=none means the domain has no SPF record. spf=permerror means the record exists but cannot be evaluated: two records on one name, more than ten DNS lookups or a syntax error, see multiple SPF records and too many DNS lookups. spf=temperror is a DNS failure that may clear on its own.
How the test reports it
In the SPF check a softfail is a warning rather than a failure, because ~all asked for exactly that. Next to it are the envelope domain that was checked, the sending IP and the receiving server's own comment, the "domain of transitioning" line included, so the address to look up is right there.