From bb2038e8c65eaeaef20c61694fa68041de0a8d25 Mon Sep 17 00:00:00 2001 From: H4R0 Date: Mon, 21 Aug 2023 00:32:26 +0200 Subject: [PATCH] feat: Allow marking spam as read via a sieve filter (ENV `MARK_SPAM_AS_READ=1`) (#3489) * add MARK_SPAM_AS_READ environment variable * review changes Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com> * update unit test --------- Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com> --- CHANGELOG.md | 4 +++ docs/content/config/environment.md | 12 +++++++++ docs/content/config/security/rspamd.md | 1 + mailserver.env | 3 +++ target/scripts/start-mailserver.sh | 1 + .../scripts/startup/setup.d/security/misc.sh | 25 +++++++++++++++++++ target/scripts/startup/variables-stack.sh | 1 + .../set1/spam_virus/spam_junk_folder.bats | 23 +++++++++++++++++ 8 files changed, 70 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1332976..028bffe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ All notable changes to this project will be documented in this file. The format > **Note**: Changes and additions listed here are contained in the `:edge` image tag. These changes may not be as stable as released changes. +### Added + +- New environment variable `MARK_SPAM_AS_READ`. When set to `1`, marks incoming junk as "read" to avoid unwanted notification of junk as new mail ([#3489](https://github.com/docker-mailserver/docker-mailserver/pull/3489)) + ## [v12.1.0](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v12.1.0) ### Added diff --git a/docs/content/config/environment.md b/docs/content/config/environment.md index b81cef12..bea02ecb 100644 --- a/docs/content/config/environment.md +++ b/docs/content/config/environment.md @@ -309,6 +309,18 @@ will be automatically moved to the Junk folder (with the help of a Sieve script) - 0 => Spam messages will be delivered in the mailbox. - **1** => Spam messages will be delivered in the `Junk` folder. +##### MARK_SPAM_AS_READ + +Enable to treat received spam as "read" (_avoids notification to MUA client of new mail_). + +Mail is received as spam when it has been marked with either header: + +1. `X-Spam: Yes` (_by Rspamd_) +2. `X-Spam-Flag: YES` (_by SpamAssassin - requires [`SPAMASSASSIN_SPAM_TO_INBOX=1`](#spamassassin_spam_to_inbox)_) + +- **0** => disabled +- 1 => Spam messages will be marked as read + #### Rspamd ##### ENABLE_RSPAMD diff --git a/docs/content/config/security/rspamd.md b/docs/content/config/security/rspamd.md index d1d0987e..7876b998 100644 --- a/docs/content/config/security/rspamd.md +++ b/docs/content/config/security/rspamd.md @@ -27,6 +27,7 @@ The following environment variables are related to Rspamd: 6. [`RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE`](../environment.md#rspamd_hfilter_hostname_unknown_score) 7. [`RSPAMD_LEARN`](../environment.md#rspamd_learn) 8. [`MOVE_SPAM_TO_JUNK`](../environment.md#move_spam_to_junk) +9. [`MARK_SPAM_AS_READ`](../environment.md#mark_spam_as_read) With these variables, you can enable Rspamd itself and you can enable / disable certain features related to Rspamd. diff --git a/mailserver.env b/mailserver.env index cb040b9f..6f270af4 100644 --- a/mailserver.env +++ b/mailserver.env @@ -368,6 +368,9 @@ ENABLE_SPAMASSASSIN_KAM=0 # spam messages will be moved in the Junk folder (SPAMASSASSIN_SPAM_TO_INBOX=1 required) MOVE_SPAM_TO_JUNK=1 +# spam messages wil be marked as read +MARK_SPAM_AS_READ=0 + # add spam info headers if at, or above that level: SA_TAG=2.0 diff --git a/target/scripts/start-mailserver.sh b/target/scripts/start-mailserver.sh index a002c6c3..e41ae71e 100755 --- a/target/scripts/start-mailserver.sh +++ b/target/scripts/start-mailserver.sh @@ -48,6 +48,7 @@ function _register_functions() { _register_setup_function '_setup_dovecot_dhparam' _register_setup_function '_setup_dovecot_quota' _register_setup_function '_setup_spam_to_junk' + _register_setup_function '_setup_spam_mark_as_read' fi case "${ACCOUNT_PROVISIONER}" in diff --git a/target/scripts/startup/setup.d/security/misc.sh b/target/scripts/startup/setup.d/security/misc.sh index b1fa4860..78c1e60a 100644 --- a/target/scripts/startup/setup.d/security/misc.sh +++ b/target/scripts/startup/setup.d/security/misc.sh @@ -271,3 +271,28 @@ EOF _log 'debug' 'Spam emails will not be moved to the Junk folder' fi } + +function _setup_spam_mark_as_read() { + if [[ ${MARK_SPAM_AS_READ} -eq 1 ]]; then + _log 'debug' 'Spam emails will be marked as read' + mkdir -p /usr/lib/dovecot/sieve-global/after/ + + # Header support: `X-Spam-Flag` (SpamAssassin), `X-Spam` (Rspamd) + cat >/usr/lib/dovecot/sieve-global/after/spam_mark_as_read.sieve << EOF +require ["mailbox","imap4flags"]; + +if anyof (header :contains "X-Spam-Flag" "YES", + header :contains "X-Spam" "Yes") { + setflag "\\\\Seen"; +} +EOF + sievec /usr/lib/dovecot/sieve-global/after/spam_mark_as_read.sieve + chown dovecot:root /usr/lib/dovecot/sieve-global/after/spam_mark_as_read.{sieve,svbin} + + if [[ ${ENABLE_SPAMASSASSIN} -eq 1 ]] && [[ ${SPAMASSASSIN_SPAM_TO_INBOX} -eq 0 ]]; then + _log 'warning' "'SPAMASSASSIN_SPAM_TO_INBOX=0' but it is required to be 1 for 'MARK_SPAM_AS_READ=1' to work" + fi + else + _log 'debug' 'Spam emails will not be marked as read' + fi +} diff --git a/target/scripts/startup/variables-stack.sh b/target/scripts/startup/variables-stack.sh index d6c5453c..a0d61242 100644 --- a/target/scripts/startup/variables-stack.sh +++ b/target/scripts/startup/variables-stack.sh @@ -46,6 +46,7 @@ function __environment_variables_general_setup() { VARS[CLAMAV_MESSAGE_SIZE_LIMIT]="${CLAMAV_MESSAGE_SIZE_LIMIT:=25M}" VARS[FAIL2BAN_BLOCKTYPE]="${FAIL2BAN_BLOCKTYPE:=drop}" VARS[MOVE_SPAM_TO_JUNK]="${MOVE_SPAM_TO_JUNK:=1}" + VARS[MARK_SPAM_AS_READ]="${MARK_SPAM_AS_READ:=0}" VARS[POSTGREY_AUTO_WHITELIST_CLIENTS]="${POSTGREY_AUTO_WHITELIST_CLIENTS:=5}" VARS[POSTGREY_DELAY]="${POSTGREY_DELAY:=300}" VARS[POSTGREY_MAX_AGE]="${POSTGREY_MAX_AGE:=35}" diff --git a/test/tests/parallel/set1/spam_virus/spam_junk_folder.bats b/test/tests/parallel/set1/spam_virus/spam_junk_folder.bats index 237218e8..94a9b9c4 100644 --- a/test/tests/parallel/set1/spam_virus/spam_junk_folder.bats +++ b/test/tests/parallel/set1/spam_virus/spam_junk_folder.bats @@ -8,6 +8,7 @@ BATS_TEST_NAME_PREFIX='[Spam - Amavis] ENV SPAMASSASSIN_SPAM_TO_INBOX ' CONTAINER1_NAME='dms-test_spam-amavis_bounced' CONTAINER2_NAME='dms-test_spam-amavis_env-move-spam-to-junk-0' CONTAINER3_NAME='dms-test_spam-amavis_env-move-spam-to-junk-1' +CONTAINER4_NAME='dms-test_spam-amavis_env-mark-spam-as-read-1' function teardown() { _default_teardown ; } @@ -69,6 +70,28 @@ function teardown() { _default_teardown ; } _should_receive_spam_at '/var/mail/localhost.localdomain/user1/.Junk/new/' } +# NOTE: Same as test for `CONTAINER3_NAME`, only differing by ENV `MARK_SPAM_AS_READ=1` + `_should_receive_spam_at` location +@test "(enabled + MARK_SPAM_AS_READ=1) should mark spam message as read" { + export CONTAINER_NAME=${CONTAINER4_NAME} + + local CUSTOM_SETUP_ARGUMENTS=( + --env ENABLE_AMAVIS=1 + --env ENABLE_SPAMASSASSIN=1 + --env SA_SPAM_SUBJECT="SPAM: " + --env SPAMASSASSIN_SPAM_TO_INBOX=1 + --env MARK_SPAM_AS_READ=1 + --env PERMIT_DOCKER=container + ) + _init_with_defaults + _common_container_setup 'CUSTOM_SETUP_ARGUMENTS' + + _should_send_spam_message + _should_be_received_by_amavis 'Passed SPAM {RelayedTaggedInbound,Quarantined}' + + # Should move delivered spam to Junk folder as read (`cur` instead of `new`) + _should_receive_spam_at '/var/mail/localhost.localdomain/user1/.Junk/cur/' +} + function _should_send_spam_message() { _wait_for_smtp_port_in_container _wait_for_tcp_port_in_container 10024 # port 10024 is for Amavis