Cloudron mail app version: cloudron/mail 3.18.2 (SpamAssassin 4.0.0, 2022-12-13)
Summary
There is no GUI (or API) way to whitelist a trusted sender domain in the Cloudron mail app — the only exposed mechanism is the free-text "Custom SpamAssassin rules" field, which maps directly to /app/data/spamd/custom.cf (included from local.cf). While investigating recurring false positives on legitimate Microsoft 365 senders, I found that the relay-verified whitelist directive (whitelist_from_rcvd / its current alias welcomelist_from_rcvd, including the def_ variants) does not fire at all in this setup — confirmed on both long-standing entries and newly added ones. The unauthenticated variant (welcomelist_from, From-header only, no relay check) works correctly.
Environment
- Cloudron mail app 3.18.2, SpamAssassin 4.0.0
- spamd invocation (from
ps) :/usr/sbin/spamd --max-children 2 --port 7833 --nouser-config --virtual-config /app/data/spamd/%u --syslog stderr -u cloudron --allow-tell /etc/spamassassin/local.cf(shipped, resets on update) includes two persistent files under/app/data/spamd/:acl.cf(GUI-managed sender allow/blocklist) andcustom.cf(GUI "Custom SpamAssassin rules" free-text field — this is the only place available forscore/whitelist tuning).- No
trusted_networks/internal_networksdirective is present anywhere in the shipped config (local.cf,*.prefiles) or incustom.cf.
Steps to reproduce
- In the mail app's "Custom SpamAssassin rules" field, add:
def_whitelist_from_rcvd *@outlook.com *.protection.outlook.com - Save (this restarts spamd — confirmed via
ps -o etimeon the spamd process). - Take a real inbound message from an
*@outlook.comsender that passed through*.protection.outlook.comrelays (verified via the Received headers). - Re-score it:
docker exec mail spamassassin -t < message.eml - Observe
X-Spam-Status— noUSER_IN_WELCOMELIST/USER_IN_DEF_WHITELIST(deprecated alias) test appears, and the score is identical to a run with the whitelist line removed.
Repeated with:
- A newly added entry for a specific business partner domain (
def_whitelist_from_rcvd *@example.nl *.protection.outlook.com) on a real message from that domain — same result, rule does not fire. - The current directive name instead of the deprecated alias (
def_welcomelist_from_rcvd *@example.nl *.protection.outlook.com) — same result. - A synthetic minimal
.emlwith a single clean Received header (from HOST.outbound.protection.outlook.com (mail-....outbound.protection.outlook.com [IP]) by my.<domain> (Haraka) ...) and a matching From address — same result. SpamAssassin's own debug log correctly identifies this Received header as__LAST_UNTRUSTED_RELAY_NO_AUTH(i.e. it does parse the relay boundary correctly), yet the whitelist rule still does not fire.
Control test (confirms the mechanism itself, isolates the bug)
spamassassin -t --cf="welcomelist_from *@example.nl" < message.eml
→ X-Spam-Status: No, score=-100.0 ... tests=...,USER_IN_WELCOMELIST — fires immediately and correctly, at the rule's hardcoded default score of -100.
So: the address-only, non-relay-verified directive works reliably; the relay-verified directive (which is presumably intended to be the "safe" option, since it additionally confirms the mail actually arrived via the claimed infrastructure, not just a forged From: header) never fires, in this container/config, regardless of naming (whitelist_from_rcvd vs welcomelist_from_rcvd) or entry age (default-shipped vs newly added).
Suspected cause
_check_welcomelist_rcvd (in Mail::SpamAssassin::Plugin::WLBLEval, called from check_from_in_default_welcomelist) presumably relies on SpamAssassin's own trusted/internal relay boundary detection to know which Received header to compare against the second (origin) parameter. Since this Cloudron config declares no trusted_networks / internal_networks, that auto-detection may be picking the wrong boundary or failing silently for this reason — even though the same debug run shows SpamAssassin does correctly tag the relevant Received header as the last untrusted relay via a different, unrelated eval (__LAST_UNTRUSTED_RELAY_NO_AUTH). I have not been able to fully confirm this from the plugin source in the time available; posting here in case someone has already solved this or knows the missing config.
Workaround in use
Switched the partner-domain entries to the non-relay-verified directive with a tuned-down score (rather than the default -100, which would let a spoofed From: header fully bypass filtering):
score USER_IN_WELCOMELIST -4.0
welcomelist_from *@example.nl
This is good enough to counter a BAYES/HELO false-positive but does not fully bypass SPF/DKIM/DNSBL-driven detection the way the (non-working) relay-verified version was intended to. It's a knowingly weaker mechanism (spoofable From header) — would much prefer the relay-verified variant to actually work.
Ask
- Is
whitelist_from_rcvd/welcomelist_from_rcvdknown to be broken in this SpamAssassin/Cloudron combination, and if so is there a missing config directive (e.g.trusted_networks) that should be shipped by default or that we should add ourselves incustom.cf? - Separately: is there any plan for a proper GUI/API-level "trusted sender domain" feature in the mail app, so this doesn't require hand-editing SpamAssassin rule syntax in a free-text field?
Happy to provide more debug output / test further if useful.



?