Default rule set: MID_RHS_MATCH_FROM is scored +1.00 although it identifies a well-formed sender

Issue Description

This concerns the default rule set distributed via spamFilterRulesUrl
(spam-filter-rules.json.gz), not the server code.

MID_RHS_MATCH_FROM is scored +1.00. The tag fires when the Message-ID
host matches the From domain — conventional, correct sender behaviour,
not a spam indicator. The result is a flat one-point penalty applied to
well-configured senders.

The same loop that produces it also produces MID_RHS_MATCH_ENV_FROM, for
the envelope-from identity. That tag has no score entry at all, i.e. 0.00.
Two tags expressing the same property against two identities, only one
of which is penalised — which is what makes me think the +1.00 is
unintended rather than a deliberate heuristic.

Expected Behavior

A Message-ID whose right-hand side matches the From domain should be
scored neutrally, or negatively if the original intent was to reward the
match. It should not push a message toward the spam threshold.

Actual Behavior

MID_RHS_MATCH_FROM contributes +1.00 to the final score.

Two legitimate messages received on a production server, default
threshold 5.0, both classified as spam, both carrying the tag:

  • Microsoft 365 tenant, spf=pass aligned, dkim=pass — score 7.10
  • Government service notification, spf=pass aligned,
    dkim=pass aligned — score 5.80

In the second case, removing this tag alone yields 4.80, i.e. below
threshold: it is the difference between inbox and junk. In both, the
Message-ID domain matched the From domain exactly.

Reproduction Steps

  1. Run with the default rule set (no local SpamTag overrides).
  2. Receive any message whose Message-ID host equals the From domain —
    which is what most correctly configured senders produce.
  3. Inspect X-Spam-Result on the delivered message: it lists
    MID_RHS_MATCH_FROM (1.00).
  4. Compare with MID_RHS_MATCH_ENV_FROM, which appears at (0.00).

Relevant Log Output

sample 1 — Microsoft 365 tenant

X-Spam-Result: DKIM_ALLOW (-0.20), SPF_ALLOW (-0.20),
MID_RHS_MATCH_ENV_FROM (0.00),
DMARC_NA (1.00), HELO_IPREV_MISMATCH (1.00),
MID_RHS_MATCH_FROM (1.00), MIME_BASE64_TEXT_BOGUS (1.00),
PYZOR (3.50)
X-Spam-Score: spam, score=7.10

sample 2 — government service notification

X-Spam-Result: DKIM_ALLOW (-0.20), SPF_ALLOW (-0.20),
MID_RHS_MATCH_ENV_FROM (0.00),
MIME_HTML_ONLY (0.20), DMARC_NA (1.00),
MID_RHS_MATCH_FROM (1.00), PHISHING (4.00)
X-Spam-Score: spam, score=5.80

Stalwart Version

v0.16.x

Installation Method

Binary (Linux)

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

Internal

Additional Context

The tag is emitted at crates/spam-filter/src/analysis/messageid.rs:62-76
(v0.16.20):

for (part, sender) in [
    ("FROM", &ctx.output.from.email),
    ("ENV_FROM", &ctx.output.env_from_addr),
] {
    if !sender.address.is_empty() {
        if mid.contains(sender.address.as_str()) {
            ctx.result.add_tag(format!("MID_CONTAINS_{part}"));
        } else if mid_host.fqdn == sender.domain_part.fqdn {
            ctx.result.add_tag(format!("MID_RHS_MATCH_{part}"));
        } else if /* SLD match */ {
            ctx.result.add_tag(format!("MID_RHS_MATCH_{part}TLD"));
        }
    }
}

Scores in the current rule set:

MID_RHS_MATCH_FROM 1.0
MID_RHS_MATCH_ENV_FROM no entry (0.0)

Suggested fix: score MID_RHS_MATCH_FROM at 0.0, or negative if rewarding
the match was the intent. If the +1.00 is deliberate, documenting the
reasoning and scoring MID_RHS_MATCH_ENV_FROM consistently would help.

Happy to provide full headers for both samples.

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

This is a well-founded observation about the default rule set’s scoring rather than a documented behavior I can confirm as intentional, so I don’t have grounds to say whether it’s a bug or deliberate. I’ll answer with the workaround while flagging the report for follow-up.

You’ve correctly identified an asymmetry in the default rule set: MID_RHS_MATCH_FROM carries a +1.00 score while its sibling MID_RHS_MATCH_ENV_FROM has no entry (0.00), even though both simply indicate the Message-ID host matches a sender identity domain, which is normal for well-configured mail. I can’t find any documented rationale in the current docs for why the two are scored differently, so this looks like it may indeed be an oversight in the shipped rule set rather than a deliberate design choice — a human maintainer will need to confirm and adjust it upstream.

In the meantime, you can neutralize this locally without waiting for an update to the shipped rule set: define a SpamTag override for MID_RHS_MATCH_FROM (e.g. set its score to 0.00, or negative if you want to reward the match) via the WebUI under Settings › Spam Filter › Scores, or by applying it through the JMAP/CLI API as a SpamTag object. This overrides the value from the downloaded spam-filter-rules.json.gz for your instance.

Reference: Scores | Stalwart and SpamTag | Stalwart

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

Correction to my own report. The argument I built on the absence of MID_RHS_MATCH_ENV_FROM does not hold: Rspamd’s rules/mid.lua has no ENV_FROM variants at all, so their absence here is a porting artifact and says nothing about intent. MID_RHS_MATCH_FROMTLD is also present at 0.0, which further undercuts what I wrote.

There is a stronger and simpler point, though. Upstream sets this symbol to zero explicitly:

rspamd_config:register_virtual_symbol('MID_RHS_MATCH_FROM', 1.0, check_mid_id)
rspamd_config:set_metric_symbol('MID_RHS_MATCH_FROM', 0.0,
    'Message-ID RHS matches From domain', 'default', 'Message ID')

The registration weight and the metric score differ, and this rule set carries the former. The same divergence affects MID_MISSING_BRACKETS and MID_RHS_IP_LITERAL (0.5 upstream, 1.0 here). Publicly available Rspamd scan outputs show the symbol at (0.00) on both legitimate Microsoft 365 mail and on a message scoring 17.05, which is consistent with upstream treating it as non-discriminating.

If the 1.0 is a deliberate retuning against your own corpus, that is a perfectly good answer — I would just suggest documenting it.