Make the message context sent to the LLM configurable in the WebUI

Feature request: Make the message context sent to the LLM configurable in the WebUI

Following our recent testing of Stalwart’s built-in LLM spam classifier, I would like to suggest making the message context supplied to the LLM configurable in the WebUI.

I described our practical tests in a separate General post. The short version is that we found significant classification improvements simply by giving the model additional message metadata that Stalwart already has available internally.

Currently, according to the documentation and our inspection of the LLM request, the classifier primarily supplies the subject and selected message body to the AI model.

For our licensed Stalwart Enterprise installation, we experimentally modified the LLM integration to additionally provide:

From:
To:
Envelope-To:

This produced two interesting A/B results with the same model, prompt and temperature.

Example 1: sender context

A phishing-style message claimed to be from Commerzbank:

From: Commerzbank Support <[email protected]>
Subject: Ihre neue Commerzbank Card – Jetzt aktivieren

Without From: available to the LLM:

Legitimate,High,NORMAL_MESSAGE

After adding From::

Harmful,Medium,UNEXPECTED_ACTION

Example 2: recipient mismatch

A promotional/spam message contained:

To: [email protected]

but was actually delivered through SMTP to:

Envelope-To: [email protected]

A comparable message had previously been classified as:

Commercial,High,COMMERCIAL_OFFER

With both To: and Envelope-To: available to the LLM, our controlled test produced:

Harmful,High,UNEXPECTED_ACTION

Suggested WebUI option

It would be useful if administrators could select which message information is supplied to the LLM under:

Settings > Spam Filter > LLM Classifier

For example:

LLM message context

Content
☑ Subject
☑ Body

Addresses
☑ From
☑ To
☑ Envelope-To
☑ Reply-To

Authentication
☐ SPF result
☐ DKIM result
☐ DMARC result

The selected values could be appended to the LLM input using stable, explicit labels such as:

From: ...
To: ...
Envelope-To: ...
Reply-To: ...
SPF: pass
DKIM: pass
DMARC: pass
Subject: ...
Body:
...

This would have several advantages:

  • administrators could decide how much context the model receives;

  • token usage could remain under their control;

  • privacy-sensitive installations could enable only the fields they consider appropriate;

  • different local or hosted models could use the same structured context;

  • useful information already available inside Stalwart could be exposed to the semantic classifier without requiring local source modifications.

I would especially suggest supporting Reply-To in addition to the three fields we tested, as a discrepancy between From and Reply-To can be highly relevant for phishing detection.

SPF, DKIM and DMARC results could also be useful as optional context. They should of course be treated as evidence rather than proof that a message is legitimate: correctly authenticated domains can still send spam or malicious messages.

For a conservative default, I would suggest enabling:

Subject
Body
From
To
Envelope-To
Reply-To

while leaving authentication context optional.

Our main observation from the tests was that improving the information available to the LLM can materially improve classification without requiring a larger model or a different prompt.

A configurable message-context section in the existing LLM Classifier WebUI would also remove the need for local source patches when administrators want to experiment with these signals.

A short follow-up from real production use, since we have now been running the modified LLM context on our mail server for a while.

The results so far strongly confirm the A/B tests described above.

We are using a local Mistral model with Stalwart’s LLM classifier and currently provide the additional message context from our local patch. In normal mail, the classifier has been remarkably reliable, including mailing-list messages with somewhat messy technical characteristics:

X-Spam-LLM: LEGITIMATE (NORMAL_MESSAGE)
LLM_LEGITIMATE_HIGH (-3.00)

More importantly, we have now seen several real phishing messages where the additional semantic classification made the difference between Inbox and Spam.

Two recent examples:

1. Fake cooperative-bank security message

From: VR-ONLINE <[email protected]>

SPF:   pass
DKIM:  pass
DMARC: pass

Stalwart score without LLM:  4.49
LLM: HARMFUL_HIGH           +3.00
Final score:                 7.49

and:

2. Fake N26 security update

From: N26 Support <[email protected]>

SPF:   pass
DKIM:  pass
DMARC: pass

Stalwart score without LLM:  3.70
LLM: HARMFUL_HIGH           +3.00
Final score:                 6.70

Our spam threshold is 6, so both messages would have reached the Inbox without the LLM contribution.

These are particularly interesting examples because SPF, DKIM and DMARC all passed. The authentication results correctly established that the sending domains were authorized to send the messages — but of course they could not establish that sportsbooksnation.com was really a cooperative bank or that fahrschuleyorulmaz.de was really N26.

That is exactly where providing the LLM with message identity/context becomes valuable.

We also encountered unsolicited commercial mail where the LLM correctly returned:

UNSOLICITED (COMMERCIAL_OFFER)

even though the conventional score was very low.

So after moving from controlled tests to real production traffic, my original request remains the same, but I would now argue for it even more strongly:

Please make the message context supplied to the LLM configurable in the WebUI.

At minimum I would still suggest:

Subject
Body
From
To
Envelope-To
Reply-To

with SPF, DKIM and DMARC available as optional additional context.

The important point from our production experience is that the LLM does not replace Stalwart’s existing spam mechanisms. It adds a semantic layer that is especially useful when a technically well-authenticated message is impersonating another organisation or is otherwise misleading.

Making this context configurable would allow other administrators to obtain the same benefit without maintaining a local source patch.

One more real-world example from today which further supports the request above.

Another phishing message impersonating Volksbanken Raiffeisenbanken arrived with:

From: VR-ONLINE <[email protected]>

SPF:   pass
DKIM:  pass
DMARC: pass

The LLM correctly classified it as:

X-Spam-LLM: HARMFUL (UNEXPECTED_ACTION)
LLM_HARMFUL_HIGH (+3.00)

However, the conventional Stalwart score before the LLM contribution was only about 0.49.

So the final result was:

0.49 + 3.00 = 3.49

With our spam threshold set to 6, the message still reached the Inbox despite the LLM having correctly identified it as harmful.

The message was clearly impersonating a bank, requested an urgent Online Banking security update and linked to a storage.googleapis.com URL rather than a banking domain.

This is another good example of why the additional sender/message context is useful: the LLM classification itself was correct even though SPF, DKIM and DMARC all passed.

This production experience suggests one additional improvement which may deserve separate consideration:

Make the score contribution of the LLM classifications configurable.

Stalwart already distinguishes different LLM results such as:

LLM_HARMFUL_HIGH
LLM_HARMFUL_MEDIUM
LLM_HARMFUL_LOW

LLM_UNSOLICITED_HIGH
LLM_COMMERCIAL_HIGH
LLM_LEGITIMATE_HIGH
...

At the moment, for example, LLM_HARMFUL_HIGH contributes a fixed +3.

Our recent production results show why administrator-configurable weights would be useful:

Phishing #1:
classic score  4.49
LLM             +3
final           7.49  -> Spam

Phishing #2:
classic score  3.70
LLM             +3
final           6.70  -> Spam

Phishing #3:
classic score  0.49
LLM             +3
final           3.49  -> Inbox

In all three cases the LLM classification was correct. The difference was only how much evidence the conventional spam filter had already accumulated.

We have also seen the opposite direction work well: LLM_LEGITIMATE_HIGH (-3) provides useful additional protection against false positives for legitimate messages.

Therefore it would be very useful if administrators could configure the score assigned to each LLM class/confidence combination in the WebUI, while keeping the current values as defaults.

For example:

HARMFUL_HIGH       +x
HARMFUL_MEDIUM     +x
HARMFUL_LOW        +x

UNSOLICITED_HIGH   +x
COMMERCIAL_HIGH    +x

LEGITIMATE_HIGH    -x
...

Different LLM models, mail populations and spam thresholds may require different calibration. Making these weights configurable would allow the semantic classifier to be tuned without modifying Stalwart’s source code or changing the LLM prompt.