The deliverability score: what Mailclutch checks on every captured message, and how the number is built
Every captured message gets a score out of 100. This is exactly what goes into it — SPF, DKIM, DMARC, BIMI, List-Unsubscribe, X-Priority and a SpamAssassin pass — with the weight of each rule, what a sandbox result says about production, and how to use the score as a gate in staging.
Every message that lands in a Mailclutch inbox is analysed on arrival, and one of the things you see next to it is a number: a deliverability score out of 100. A number on its own is not very useful, so this article opens it up — which checks run, what each one is worth, why the weights are what they are, and what the result means given that it was measured in a sandbox rather than at Gmail.
We are publishing the weights because a score you cannot reason about is a score you cannot act on. The value is never the number; it is the list of rules underneath it and the diff between two sends.
The rules
The calculator starts at 100 and applies a list of rules. Each rule looks at one aspect of the message and returns a status — pass, warning, fail or neutral — and an impact, positive or negative. The impacts are summed, the result is clamped to 0–100, and the rules are listed with their findings.
Authentication
| Rule | Result | Impact |
|---|---|---|
| SPF | Pass | 0 |
| Neutral / none (no record for the sender domain) | −10 | |
| Softfail | −10 | |
| Fail | −25 | |
| Permerror / temperror | −5 | |
| DKIM | Valid signature | 0 |
| No signature | −10 | |
| Signature present, does not verify | −25 | |
| Signature present, unaligned or malformed | −5 to −10 | |
| DMARC | Pass | 0 |
| No record on the From domain | −5 | |
| Fail | −20 | |
Record present, policy none or unevaluable |
−5 | |
| BIMI | Record with logo and certificate | +5 |
| Record with logo, no certificate | +3 | |
| No record, or incomplete record | 0 |
A DKIM signature that fails costs more than no signature at all — deliberately. Absence says "this sender has not set up DKIM". A failing signature says "something between the signer and the receiver modified the message", which is a defect to find, and one that a receiver weighs heavily. The same logic applies to SPF fail versus none.
BIMI is the one rule with a positive impact, and it is small. A logo is a marker of a domain that has finished its authentication work; it is not a deliverability mechanism, and the score reflects that. See BIMI explained for what the two states mean.
Content and headers
| Rule | Result | Impact |
|---|---|---|
| List-Unsubscribe | Both headers (one-click, RFC 8058) | +5 |
List-Unsubscribe alone |
+3 | |
| Neither | 0 | |
| X-Priority | Absent or normal | 0 |
| High priority / urgent flag set | −5 |
List-Unsubscribe is scored as a bonus rather than a penalty because its correct value depends on the message: subscribed mail should carry it, transactional mail should not, and the calculator does not know which it is looking at. The rule reports what it found; which state is right is your decision.
X-Priority: 1 and its cousins (Importance: high, X-MSMail-Priority: High) are a small, consistent negative at most receivers — a legitimate transactional sender has no reason to flag urgency at the transport layer.
Spam analysis
| Rule | Result | Impact |
|---|---|---|
| SpamAssassin | Score below 60% of the threshold | 0 |
| Score above 60% of the threshold, below it | −10 | |
| Score at or above the threshold | −30 | |
| SpamAssassin unavailable | 0 (neutral, reported as such) |
The threshold is SpamAssassin's own, 5.0 by default, so the warning band starts at 3.0. The reasoning is in SpamAssassin scores explained: a message at 3.5 is one rule away from filtering, and we would rather say so than round it to "fine". The individual rules that fired are listed with the result, because that list is the fix.
Two messages, two scores
A receipt sent from a staging environment with a hand-rolled SMTP client:
Score: 54 SPF neutral No SPF record for staging.example.internal −10 DKIM fail No DKIM signature −10 DMARC warning No DMARC record for example.com −5 BIMI neutral No BIMI record 0 List-Unsub neutral No List-Unsubscribe header 0 X-Priority fail X-Priority: 1 (Highest) −5 SpamAssassin warning High SpamAssassin score (3.7/5.0) −10 MISSING_MID, MISSING_DATE, SUBJ_ALL_CAPS, HTML_IMAGE_ONLY_24
The same receipt after the mailer was switched to the framework's, DKIM signing was enabled on the provider, the subject was fixed and the priority header removed:
Score: 95 SPF neutral No SPF record for staging.example.internal −10 DKIM pass Valid signature, d=example.com 0 DMARC pass Aligned via DKIM 0 BIMI pass Record with logo (no VMC) +3 List-Unsub neutral No List-Unsubscribe header 0 X-Priority pass 0 SpamAssassin pass 1.2/5.0 0
The remaining −10 is SPF on the staging host — which is the next section.
What a sandbox result means
A sandbox is not the production sending path, and the score has to be read with that in mind. The rules split into two kinds.
Rules about the message transfer directly to production. DKIM — is it signed, on which domain, does it verify — is a property of the message as your code and your provider produced it. So is everything SpamAssassin sees in the headers and body, the presence of List-Unsubscribe, the priority flag, and the DMARC alignment between the From domain and the DKIM domain. If these pass in the sandbox, they pass at Gmail. If they fail, they fail everywhere.
Rules about the sending host describe the host you tested from. SPF is evaluated against the IP that connected to the sandbox — your staging server, a CI runner, a laptop — which is not in your SPF record and should not be. RDNS_NONE in the SpamAssassin result is the same story. These results are correct for the message you sent; they just describe staging.
So the reading is: fix everything in the first group until it is clean, and treat the second group as a reminder of what production DNS has to provide. A staging score that plateaus at 90 with only SPF outstanding is a message that is ready.
Using the score as a gate
The score exists so that a change to how mail is sent is visible as a change. The pattern that works:
- Staging sends every message it would send in production — through the sandbox, so nothing reaches a real inbox.
- Each captured message has a score and a rule list.
- When the score moves, the rule list says why, and the pull request that moved it is the one currently deployed to staging.
The same analysis is available programmatically — the REST API returns it for any captured message, and the MCP server exposes it as a check_deliverability tool — which is what makes it usable from CI: send the fixture, wait for the capture, assert on the score or on specific rules. "DKIM must pass" and "SpamAssassin must be under 3.0" are assertions a test suite can make, and they are the assertions that would have caught most of the sender-requirement failures we see.
What is deliberately not in the score
- Rendering. Whether the HTML looks right in Outlook is a separate panel, and a separate kind of problem.
- Link checks. Broken links are checked, but they are not deliverability.
- Content heuristics of our own. The spam-content analysis is SpamAssassin's, unmodified, because its rules are public and its results are explainable. A proprietary score with no rule list would be a number you could not argue with.
- Reputation. See above.
Reading the score, in one sentence
The number is a summary; the rule list is the finding; the diff between two sends is the reason you have a sandbox in the first place.