Show what the spam filter said, in the message details #196

Open
opened 2026-09-02 04:45:48 +00:00 by jcoffey-dev · 0 comments
Owner

The filter in front of the mailbox scores every delivered message and writes its working into headers, and none of it was being read. A message sitting in Junk gave no reason for being there.

What it does

Parses the spam headers already on the message and shows them in the details panel: verdict, score, the threshold it was measured against, and the rules that moved it — largest mover first, signed, so which way each one pushed is visible.

Nothing here scores anything. The server already did that at delivery, so this cannot disagree with the filter that actually made the decision, and it costs no extra request — three header properties added to FULL_PROPS.

Two formats are read: the SpamAssassin-shaped X-Spam-* set that Stalwart's own filter writes, and Rspamd's X-Spamd-Result. A header in neither shape is left unread rather than guessed at — a misparsed score shown confidently is worse than no panel. Mail without any of them shows nothing at all.

Two things it deliberately will not do

A score is never shown without its threshold where the header stated one. 6.7 is damning against a threshold of 5 and unremarkable against 15, so the number alone is not something a reader can act on. Where no threshold was stated, it says so rather than implying one.

No verdict is invented. If the filter recorded one, it is shown. If it only left a score, the score is shown alone — the verdict is not derived from score against threshold, because the filter applies policy ihasmail cannot see and putting words in its mouth is not a summary. Rspamd's greylist is likewise not treated as a verdict about the message.

Mock

Writes the same headers at delivery — spam in Junk, clean in the Inbox, nothing on mail this account wrote — so the panel is demoable without a real mailbox.

Testing

13 unit tests over both formats: verdicts, negative scores, folded headers, malformed rules, precedence, the bare-score fallback, and the two refusals above. Suite green: web 616, server 110, typecheck clean.

Checked in the running app against the mock, in both dark and light themes: the spam case in Junk, the clean case in the Inbox, and a width cap so a rule with no note does not fling its score to the far side of a wide reading pane.

Merged 2026-09-01 as coffey-labs/ihasmail@1ea813940b

Rebuilt from: git history, session transcript.

The filter in front of the mailbox scores every delivered message and writes its working into headers, and none of it was being read. A message sitting in Junk gave no reason for being there. ## What it does Parses the spam headers already on the message and shows them in the details panel: verdict, score, the threshold it was measured against, and the rules that moved it — largest mover first, signed, so which way each one pushed is visible. Nothing here scores anything. The server already did that at delivery, so this cannot disagree with the filter that actually made the decision, and it costs no extra request — three header properties added to `FULL_PROPS`. Two formats are read: the SpamAssassin-shaped `X-Spam-*` set that Stalwart's own filter writes, and Rspamd's `X-Spamd-Result`. A header in neither shape is left unread rather than guessed at — a misparsed score shown confidently is worse than no panel. Mail without any of them shows nothing at all. ## Two things it deliberately will not do **A score is never shown without its threshold** where the header stated one. 6.7 is damning against a threshold of 5 and unremarkable against 15, so the number alone is not something a reader can act on. Where no threshold was stated, it says so rather than implying one. **No verdict is invented.** If the filter recorded one, it is shown. If it only left a score, the score is shown alone — the verdict is not derived from score against threshold, because the filter applies policy ihasmail cannot see and putting words in its mouth is not a summary. Rspamd's `greylist` is likewise not treated as a verdict about the message. ## Mock Writes the same headers at delivery — spam in Junk, clean in the Inbox, nothing on mail this account wrote — so the panel is demoable without a real mailbox. ## Testing 13 unit tests over both formats: verdicts, negative scores, folded headers, malformed rules, precedence, the bare-score fallback, and the two refusals above. Suite green: web 616, server 110, typecheck clean. Checked in the running app against the mock, in both dark and light themes: the spam case in Junk, the clean case in the Inbox, and a width cap so a rule with no note does not fling its score to the far side of a wide reading pane. **Merged** 2026-09-01 as coffey-labs/ihasmail@1ea813940b40 <sub>Rebuilt from: git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.