Route rspamd-tagged mail to Junk through Stalwart's spam filter #544

Merged
benvin merged 18 commits from benvin/mail-sieve-reconcile into main 2026-10-13 21:43:14 +11:00
Member

Stalwart only files mail into Junk natively when its own spam filter marks it, so rspamd-tagged mail reached Junk only for accounts with a Sieve script, and first boot loads upstream DNSBLs, HTTP lists and URL lookups.

  • enable the spam filter with one header rule scoring X-Spam: Yes above the spam threshold, covering every account including newly provisioned ones
  • remove the upstream spam rules, tags, DNSBL servers, HTTP lists and lookup keys
  • disable the classifier model and Pyzor
Stalwart only files mail into Junk natively when its own spam filter marks it, so rspamd-tagged mail reached Junk only for accounts with a Sieve script, and first boot loads upstream DNSBLs, HTTP lists and URL lookups. - enable the spam filter with one header rule scoring `X-Spam: Yes` above the spam threshold, covering every account including newly provisioned ones - remove the upstream spam rules, tags, DNSBL servers, HTTP lists and lookup keys - disable the classifier model and Pyzor
Author
Member
  • apps/base/mail/resources/sieve-reconcile.py:46 — with_include computes the end of the require block (i) but returns HEADER + lines[:i] + lines[i:], so the include always lands at the top, above the user's require. A require after a command is invalid Sieve (RFC 5228 §3.2), so every account with an existing script gets a rejected SieveScript/set and the job exits 1 every run → return "".join(lines[:i]) + HEADER + "".join(lines[i:]); the header's own require ["include"] is then also legal after the user's requires.
  • apps/base/mail/resources/sieve-reconcile.py:15 — nit: HAS_INCLUDE matches commented-out lines (# include :global "spam-to-junk"), so a commented script is treated as already done → strip # comment lines before matching.
  • apps/base/mail/resources/sieve-reconcile.py:57 — nit: page.get("total", position) ends paging after page one because calculateTotal is not requested → add "calculateTotal": True to the query.
- apps/base/mail/resources/sieve-reconcile.py:46 — `with_include` computes the end of the require block (`i`) but returns `HEADER + lines[:i] + lines[i:]`, so the include always lands at the top, above the user's `require`. A `require` after a command is invalid Sieve (RFC 5228 §3.2), so every account with an existing script gets a rejected `SieveScript/set` and the job exits 1 every run → return `"".join(lines[:i]) + HEADER + "".join(lines[i:])`; the header's own `require ["include"]` is then also legal after the user's requires. - apps/base/mail/resources/sieve-reconcile.py:15 — nit: `HAS_INCLUDE` matches commented-out lines (`# include :global "spam-to-junk"`), so a commented script is treated as already done → strip `#` comment lines before matching. - apps/base/mail/resources/sieve-reconcile.py:57 — nit: `page.get("total", position)` ends paging after page one because `calculateTotal` is not requested → add `"calculateTotal": True` to the query.
benvin changed target branch from benvin/mail-stalwart to main 2026-10-13 20:58:09 +11:00
benvin added 14 commits 2026-10-13 20:58:09 +11:00
Deploy Stalwart into the mail namespace
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
92a29b4ca9
Restart Stalwart after applying the plan; move mail DNS record out
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
7fd1ce8404
Verify the CNPG CA for Stalwart's Postgres, pin webui, bound the apply Job
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
2b992f771c
Run Stalwart as a 3-node StatefulSet coordinated through Valkey
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
eb7dbca947
Label Stalwart pods as smarthost clients
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
9a12556841
Add global spam-to-junk Sieve script
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
1e15dc4a98
Reconcile a spam-to-junk Sieve include onto every Stalwart account
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
3208973211
Stop after filing spam and exempt LMTP from inbound throttles
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
9476d369e1
Insert spam-to-junk include after the require block and self-test it
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
78c6fa7918
Merge remote-tracking branch 'origin/main' into benvin/mail-stalwart
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
f6da274325
# Conflicts:
#	apps/base/mail/kustomization.yaml
Merge remote-tracking branch 'origin/benvin/mail-stalwart' into benvin/mail-sieve-reconcile
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
b9624da169
# Conflicts:
#	apps/base/mail/kustomization.yaml
Merge remote-tracking branch 'origin/main' into benvin/mail-stalwart
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
869dfb7ccc
# Conflicts:
#	apps/base/mail/kustomization.yaml
Merge remote-tracking branch 'origin/benvin/mail-stalwart' into benvin/mail-sieve-reconcile
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
eabeb00cfa
unkin-agent added 2 commits 2026-10-13 21:12:25 +11:00
Score rspamd's X-Spam verdict in Stalwart's spam filter
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
ab1fc6c728
Replace the Sieve reconcile CronJob with Stalwart's native Junk delivery: a single header rule scores X-Spam: Yes over the spam threshold, and the upstream rules, DNSBLs, HTTP lists, lookup keys, classifier and Pyzor are removed.
unkin-agent changed title from Reconcile spam-to-junk Sieve include onto Stalwart accounts to Route rspamd-tagged mail to Junk through Stalwart's spam filter 2026-10-13 21:12:30 +11:00
unkin-agent added 1 commit 2026-10-13 21:28:22 +11:00
Merge remote-tracking branch 'origin/main' into benvin/mail-sieve-reconcile
ci/woodpecker/pr/pre-commit Pipeline failed
ci/woodpecker/pr/kubeconform Pipeline was successful
38264594a0
unkin-agent added 1 commit 2026-10-13 21:30:47 +11:00
Retrigger CI
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
0e9d95f87f
benvin merged commit bb45b20f8a into main 2026-10-13 21:43:14 +11:00
benvin deleted branch benvin/mail-sieve-reconcile 2026-10-13 21:43:14 +11:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unkin/argocd-apps#544