By default Virtualmin/Webmin ships with SpamAssassin. Rspamd can be used as a replacement for SpamAssassin, but this requires some manual configuration.

See the free usage policy of Rspamd to understand its conditions.

Install Rspamd

See the official documentation for setup instructions and different approaches. This section follows the Production: Package Installation installation method.

Note that you may also use the packages provided by Debian directly, although they’re not supported by the Rspamd project. [1] [2]

Rspamd requires Redis, so it needs to be installed additionally:

# Add Rspamd repository GPG key

# Add Rspamd repository

$ apt update

$ apt install rspamd redis-server

# Enable and start Rspamd and Redis
$ systemctl enable --now rspamd redis-server
Note
The Redis server should be secured by using the requirepass directive in /etc/redis/redis.conf.

Configuration

Rspamd

Rspamd is configured by placing files in /etc/rspamd/local.d/ and /etc/rspamd/override.d/. Never edit the other configuration files directly.

First, configure Rspamd to use the local Redis instance.

/etc/rspamd/local.d/redis.conf
# Redis connection for statistics and learning
servers = "127.0.0.1:6379";
password = "<redacted>";

Next, define the thresholds at which Rspamd should classify messages as spam.

/etc/rspamd/local.d/actions.conf
# Basic spam filtering thresholds

greylist = 4;       # Score 4-5.9: Temporarily delay suspicious messages
add_header = 6;     # Score 6-49.9: Add spam headers, deliver to inbox/spam folder
reject = 50;        # Score 50+: Reject obvious spam outright
Note
The thresholds above might be adjusted over time. Especially the reject threshold can be lowered once you’ve gained some experience.

Rspamd is able to sign messages with DKIM. This should be disabled in case this is done by e.g. OpenDKIM.

/etc/rspamd/local.d/dkim_signing.conf
enabled = false;

Since Postfix uses the Milter protocol to communicate with Rspamd, self-scan mode needs to be enabled:

/etc/rspamd/local.d/worker-proxy.inc
milter = yes;
timeout = 120s;
upstream "local" {
  default = yes;
  self_scan = yes; # Scan messages directly
}

For easier debugging, extended_spam_headers might be enabled:

/etc/rspamd/override.d/milter_headers.conf
extended_spam_headers = true;

Secure the Rspamd webinterface (http://127.0.0.1:11334) and forbid local access. See https://docs.rspamd.com/workers/controller/#passwords-encryption for instructions on how to generate a password.

/etc/rspamd/local.d/worker-controller.inc
secure_ip = null;
password = "<redacted>";

Postfix

Postfix uses Rspamd via the Milter protocol. Also see https://docs.rspamd.com/tutorials/integration/#using-rspamd-with-postfix-mta

/etc/postfix/main.cf
# Set Milter protocol version
# https://www.postfix.org/MILTER_README.html#version
milter_protocol = 6

# Configure how to handle Milter application errors
# tempfail: reject all further commands in this session with a temporary status code
# accept: receive mail as if the filter does not exist
# https://www.postfix.org/MILTER_README.html#errors
milter_default_action = accept

# Process messages arriving via SMTP with Rspamd
# https://www.postfix.org/MILTER_README.html#smtp-only-milters
smtpd_milters = inet:127.0.0.1:11332

# Process messages arriving via sendmail by Rspamd
# https://www.postfix.org/MILTER_README.html#non-smtp-milters
non_smtpd_milters = inet:127.0.0.1:11332

# Configure macros sent to Rspamd
# https://www.postfix.org/postconf.5.html#milter_mail_macros
milter_mail_macros = i {auth_type} {auth_authen} {auth_author} {mail_addr} {mail_host} {mail_mailer} {client_addr} {client_name} {auth_authen}

This concludes a very basic setup. Mails are scanned by Rspamd, but no action is taken for messages classified as spam.

Procmail

Virtualmin uses procmail to deliver messages to local mailboxes.

The following rule can be used to deliver spam messages to the user’s spam folder. Filtering is done on the X-Spam header set by Rspamd. The H flag (:0H) ensures filtering is only performed on message headers (and not the message body).

/etc/procmailrc
...

# Rspamd: deliver to spam mailbox
:0H
* ^X-Spam: Yes
$HOME/Maildir/.spam/

:0
$DEFAULT

Virtualmin/Webmin

In Virtualmin/Webmin the SpamAssassin feature should be disabled to avoid inteferences with Rspamd.

Training Rspamd Using Sieve Filters

Moving mails into or out of the spam folder can be used to train Rspamd. This can be achieved by using Sieve filters.

First, install dovecot-sieve to enable Sieve functionality for Dovecot. Afterwards, the plugin imap_sieve needs to enabled:

/etc/dovecot/conf.d/20-imap.conf
protocol imap {
  # Space separated list of plugins to load (default is global mail_plugins).
  mail_plugins = $mail_plugins imap_sieve
}
/etc/dovecot/conf.d/90-sieve.conf
plugin {
  sieve_plugins = sieve_imapsieve sieve_extprograms

  # Moving mails into the spam folder
  imapsieve_mailbox1_name = spam
  imapsieve_mailbox1_causes = COPY
  imapsieve_mailbox1_before = file:/etc/dovecot-sieve/learn-spam.sieve

  # Moving mails from the spam folder to another folder
  imapsieve_mailbox2_name = *
  imapsieve_mailbox2_from = spam
  imapsieve_mailbox2_causes = COPY
  imapsieve_mailbox2_before = file:/etc/dovecot-sieve/learn-ham.sieve

  sieve_pipe_bin_dir = /etc/dovecot-sieve
}

Following the corresponding scripts:

/etc/dovecot-sieve/learn-spam.sieve
require ["vnd.dovecot.pipe", "copy", "imapsieve"];

if header :is "X-Spam" "Yes" {
  stop;
}

pipe :copy "rspamd-learn-spam.sh";
/etc/dovecot-sieve/rspamd-learn-spam.sh
#!/bin/sh
exec /usr/bin/rspamc learn_spam -P "<redacted>"
/etc/dovecot-sieve/learn-ham.sieve
require ["vnd.dovecot.pipe", "copy", "imapsieve", "variables"];

if string "${mailbox}" "Trash" {
  stop;
}

pipe :copy "rspamd-learn-ham.sh";
/etc/dovecot-sieve/rspamd-learn-spam.sh
#!/bin/sh
exec /usr/bin/rspamc learn_ham -P "<redacted>"

Remember to compile the sieve scripts:

sievec /etc/dovecot-sieve/learn-spam.sieve
sievec /etc/dovecot-sieve/learn-ham.sieve

Further Tweaks

Prevent Forwarding of Spam

User configured mail forwarding requires a workaround as mails flagged as spam would still be forwarded. The following procmail recipe can be used on a user level to check the X-Spam header and prevent forwarding accordingly.

/home/<domain>/homes/<user>/.procmailrc
:0H
* ^X-Spam: Yes
$DEFAULT
:0c
* !^FROM_MAILER
! recipient@domain.tld