ANTISPAM(7)

πŸ“¦ version 2.0+20171229, in debian bookworm, ubuntu jammy, ubuntu noble

πŸ’– NAME πŸ’–

antispam β€” The dovecot antispam plugin. (yes bestie, this is antispam(7) and it's giving main character energy already πŸ’…)

✨ DESCRIPTION ✨

okay so picture this: the dovecot antispam plugin watches a defined spam folder (defaults to "SPAM") like it's the group chat and somebody just posted a bad take. It works together with a spam system that classifies each message as it is delivered. When the message is classified as spam, it shall be delivered to the spam folder, otherwise via the regular filtering file the user may have (maildrop, sieve, ...). Now the user has everything classified as spam in the special spam folder, everything else where it should be sorted to.

And bestie, lowkey that's not enough because our spam scanner needs training. We'll occasionally have false positives and false negatives. Now this is the point where the dovecot antispam plugin comes into play. Instead of moving mail into special folders or forwarding them to special mail addresses for retraining, the plugin offers two actions for the user:

  1. moving mail out of the SPAM folder and
  2. moving mail into the SPAM folder.

The dovecot plugin watches these actions (and additionally prohibits APPENDs to the SPAM folder, more for technical reasons than others) and tells the spam classifier that it made an error and needs to re-classify the message (as spam/not spam depending on which way it was moved.)

The advantage of this approach is that the mail ends up in the right target folder directly and needs not be touched twice. iconic behavior, no cap, periodt βœ¨πŸ’…

When other classifiers like crm114 that have an unsure state are used, the plugin can also help, it supports an unsure folder feature. The unsure folder cannot be written to, but moving out from there into a folder that is considered a spam folder will learn as spam, any other folder (except trashes) will cause learning as not-spam.

πŸ› οΈ INSTALLATION πŸ› οΈ

First copy the defconfig file to .config and edit it as necessary. You need to have the dovecot headers installed and possibly other things depending on the backend you choose. Then, assuming you have configured the INSTALLDIR correctly, simply run make install.

If you do not wish to use the install target, simply copy the plugin (that is, the file lib90_antispam_plugin.so) to your dovecot imap plugin directory; by default this is /usr/lib/dovecot/modules/imap/ or any dir you have configured (look for the mail_plugin_dir configuration directive.)

Open your dovecot configuration file (usually /etc/dovecot/dovecot.conf) and add the antispam plugin to the imap protocol section:

protocol imap {
    mail_plugins = antispam
    # mail_plugin_dir = /usr/lib/dovecot/modules/imap
}

🌈 BACKENDS 🌈

The plugin supports multiple backends, there are currently a few working backends included in the distribution:

πŸ¦‹ dspam executable backend (dspam specific) πŸ¦‹

This backend instantly retrains by calling dspam. There are some problems with this approach including (1) it can take a long time during which the IMAP session is blocked (2) when many users retrain many messages at once server load may spike. not the vibe check you want, fr fr

🫧 pipe backend (spam filter agnostic) 🫧

This backend simply pipes the mail to train to a process it executes. This can for example be used to send it as email to mail aliases for retraining. This backend can be very easy to set up if you already have a working setup that uses training addresses as recommended by many spam filter setups.

Since this backend simply pipes the message to a program (by default sendmail) it can also be used for all kinds of other spam filters, for example spamassassin (by calling sa-learn instead of sendmail.)

🧚 crm114 executable backend (crm114 specific) 🧚

This backend instantly retrains by calling mailreaver.crm which needs to be configured (defaulting to /bin/false!); the argument --good or --spam is given depending on how mail is moved.

You need to use the unsure folder option (see below) together with this plugin and deliver unsure mail into an unsure folder, spam mail into a spam folder and other mail regularly.

Has the same drawbacks as the dspam approach.

πŸ“ spool2dir backend (general) πŸ“

This backend spools the message into a file. No further processing is performed. You need to write an extra daemon that picks up the spooled files and trains the spam filter as appropriate. You can, for example, use incron to pick up new emails.

βš™οΈ CONFIGURATION βš™οΈ

okay so beyond the build-configuration you do in the .config file, there's a whole pile of run-time options, and the manpage lists them right there with their defaults. It's all one big plugin { ... } block β€” I'm gonna break it into chunks so your brain doesn't melt, but bestie it's the same block, I promise. πŸ’–


🌸 chunk one: the generic stuff 🌸

plugin {
    ##################
    # GENERIC OPTIONS

    # Debugging options
    # Uncomment to get the desired debugging behaviour.
    # Note that in some cases stderr debugging will not be as
    # verbose as syslog debugging due to internal limitations.
    #
    # antispam_debug_target = syslog
    # antispam_debug_target = stderr
    # antispam_verbose_debug = 1
    #
    # This can be used to get a prefix, e.g. by specifying %u in it
    # antispam_debug_prefix = "antispam: "

    # backend selection, MUST be configured first,
    # there's no default so you need to set one of
    # these options:
    # antispam_backend = crm114
    # antispam_backend = dspam
    # antispam_backend = pipe
    # antispam_backend = spool2dir

    # mail signature (used with any backend requiring a signature)
    antispam_signature = X-DSPAM-Signature

    # action to take on mails without signature
    # (used with any backend requiring a signature)
    # (we recommend only setting this to 'move' after verifying that the
    # whole setup is working)
    # antispam_signature_missing = move # move silently without training
    antispam_signature_missing = error

    # The list of folders for trash, spam and unsure can be given
    # with three options, e.g. "trash" matches the given folders
    # exactly as written, "trash_pattern" accept the * wildcard at
    # the end of the foldername, "trash_pattern_ignorecase"
    # accepts the * wildcard at the end of the foldername _and_
    # matches the name case insensitivly.

    # the *-wildcard with the following meaning:
    #    * at the end: any folder that _start_ with the string
    # e.g.:
    #    antispam_trash_pattern = deleted *;Gel&APY-schte *
    # match any folders that start with "deleted " or "GelΓΆschte "
    # match is _case_senstive_!
    #
    #    antispam_trash_pattern_ignorecase = deleted *;Gel&APY-schte *
    # match any folders that start with "deleted " or "gelΓΆschte "
    # match is _case_insenstive_, except the non-USASCII letters,
    # "ΓΆ" in this example.
    # To match the upper-case Γ–, too, you need to add yet another
    # pattern "gel&ANY-schte *", note the different UTF7 encoding:
    # &ANY- instead of &APY-.

    # semicolon-separated list of Trash folders (default unset i.e. none)
    # antispam_trash =
    # antispam_trash = trash;Trash;Deleted Items; Deleted Messages
    # antispam_trash_pattern = trash;Trash;Deleted *
    # antispam_trash_pattern_ignorecase = trash;Deleted *

    # semicolon-separated list of spam folders
    antispam_spam = SPAM
    # antispam_spam_pattern = SPAM
    # antispam_spam_pattern_ignorecase = SPAM

    # semicolon-separated list of unsure folders (default unset i.e. none)
    # antispam_unsure =
    # antispam_unsure_pattern =
    # antispam_unsure_pattern_ignorecase =

    # Whether to allow APPENDing to SPAM folders or not. Must be set to
    # "yes" (case insensitive) to be activated. Before activating, please
    # read the discussion below.
    # antispam_allow_append_to_spam = no

okay let me decode the vibe here 🧚

  • antispam_debug_target, antispam_verbose_debug and antispam_debug_prefix are your debugging knobs, all commented out by default. Note that in some cases stderr debugging will not be as verbose as syslog debugging because of internal limitations β€” it's giving "bestie the logs are lying to you a little".
  • antispam_backend is the one you literally MUST configure first. There's no default, so you have to pick one of crm114, dspam, pipe or spool2dir. No backend, no party.
  • antispam_signature is the mail signature, used with any backend that needs one, and it defaults to X-DSPAM-Signature.
  • antispam_signature_missing is what happens when a mail shows up with no signature at all. Default is error. You can set it to move (which moves it silently without training), but the manpage says only do that after you've verified the whole setup is working. Do not skip that step, I'm begging. πŸ™ˆ

and then the folder lists, which come in three flavours: plain (trash matches the given folders exactly as written), _pattern (accepts the * wildcard at the end of the foldername), and _pattern_ignorecase (accepts the * wildcard at the end and matches case-insensitively).

The * wildcard means: * at the end = any folder that starts with the string. For example antispam_trash_pattern = deleted *;Gel&APY-schte * matches any folders that start with "deleted " or "GelΓΆschte " β€” and that match is case-SENSITIVE. Meanwhile antispam_trash_pattern_ignorecase = deleted *;Gel&APY-schte * matches folders starting with "deleted " or "gelΓΆschte ", case-insensitive… except the non-USASCII letters, like "ΓΆ" in that example. And to match upper-case Γ– too you need to add yet another pattern, "gel&ANY-schte *" β€” note the different UTF7 encoding: &ANY- instead of &APY-. πŸ’…

Default folder sets, for the record: antispam_trash is unset (i.e. none), antispam_unsure is unset (i.e. none), and antispam_spam = SPAM. All three lists are semicolon-separated.

And antispam_allow_append_to_spam? It must be set to "yes" (case insensitive) to actually turn on, it defaults to no, and you should read the discussion below before you even think about it. 🚨


πŸ”₯ chunk two: backend-specific, the dspam + pipe part πŸ”₯

    ###########################
    # BACKEND SPECIFIC OPTIONS
    #

    #===================
    # dspam plugin

    # dspam binary
    antispam_dspam_binary = /usr/bin/dspam

    # semicolon-separated list of extra arguments to dspam
    # (default unset i.e. none)
    # antispam_dspam_args =
    # antispam_dspam_args = --deliver=;--user;%u  # % expansion done by dovecot
    # antispam_dspam_args = --mode=teft

    # Ignore mails where the DSPAM result header contains any of the
    # strings listed in the blacklist
    # (default unset i.e. none)
    # antispam_dspam_result_header = X-DSPAM-Result
    # semicolon-separated list of blacklisted results, case insensitive
    # antispam_dspam_result_blacklist = Virus

    # semicolon-separated list of environment variables to set
    # (default unset i.e. none)
    # antispam_dspam_env =
    # antispam_dspam_env = HOME=%h;USER=%u

    #=====================
    # pipe plugin
    #
    # This plug can be used to train via an arbitrary program that
    # receives the message on standard input. Since sendmail can be
    # such a program, it can be used to send the message to another
    # email address for training there.
    #
    # For example:
    #   antispam_pipe_program = /path/to/mailtrain
    #        (defaults to /usr/sbin/sendmail)
    #   antispam_pipe_program_args = --for;%u
    #   antispam_pipe_program_spam_arg = --spam
    #   antispam_pipe_program_notspam_arg = --ham
    #   antispam_pipe_tmpdir = /tmp
    # will call it, for example, like this:
    #   /path/to/mailtrain --for jberg --spam
    #
    # The old configuration options from when this plugin was called
    # "mailtrain" are still valid, these are, in the same order as
    # above: antispam_mail_sendmail, antispam_mail_sendmail_args,
    # antispam_mail_spam, antispam_mail_notspam and antispam_mail_tmpdir.
    #
    # Alternatively, if you need to give multiple options, you can use
    # the spam_args/notspam_args parameters (which are used in preference
    # of the singular form):
    #   antispam_pipe_program_spam_args = --spam;--my-other-param1
    #   antispam_pipe_program_notspam_args = --ham;--my-other-param2
    # which will then call
    #   /path/to/mailtrain --for jberg --spam --my-other-param1

    # temporary directory
    antispam_pipe_tmpdir = /tmp

    # spam/not-spam argument (default unset which will is not what you want)
    # antispam_pipe_program_spam_arg =
    # antispam_pipe_program_notspam_arg =

    # binary to pipe mail to
    antispam_pipe_program = /usr/sbin/sendmail
    #antispam_pipe_program_args = -f;%u@example.com # % expansion done by dovecot

dspam notes, since you asked bestie πŸ’œ: the binary is antispam_dspam_binary = /usr/bin/dspam, the extra args list is semicolon-separated and unset by default, antispam_dspam_result_header = X-DSPAM-Result says which header to look at, and antispam_dspam_result_blacklist is a semicolon-separated list of blacklisted results that's case insensitive β€” mails whose DSPAM result header contains any of those strings get ignored. Then antispam_dspam_env sets environment variables, also semicolon-separated, also unset by default.

pipe notes, because this one's iconic πŸŽ€: this plugin trains via an arbitrary program that receives the message on standard input. Since sendmail can be such a program, you can use it to send the message to another email address and train there. In the example, antispam_pipe_program defaults to /usr/sbin/sendmail, and with all those settings it'd be called like /path/to/mailtrain --for jberg --spam.

the legacy names still work, no cap β€” from back when this plugin was literally called "mailtrain". In the same order as above, they are: antispam_mail_sendmail, antispam_mail_sendmail_args, antispam_mail_spam, antispam_mail_notspam and antispam_mail_tmpdir.

and if you need multiple options, use the spam_args / notspam_args parameters β€” they're used in preference of the singular form β€” and then it calls /path/to/mailtrain --for jberg --spam --my-other-param1.

also, tiny warning: antispam_pipe_program_spam_arg and antispam_pipe_program_notspam_arg are unset by default, which is not what you want. Set them. πŸ™


✨ chunk three: crm114 + spool2dir, and the closing brace ✨

    #===================
    # crm114 plugin

    # mailreaver binary
    antispam_crm_binary = /bin/false
    # antispam_crm_binary = /usr/share/crm114/mailreaver.crm

    # semicolon-separated list of extra arguments to crm114
    # (default unset i.e. none)
    # antispam_crm_args =
    # antispam_crm_args = --config=/path/to/config

    # semicolon-separated list of environment variables to set
    # (default unset i.e. none)
    # antispam_crm_env =
    # antispam_crm_env = HOME=%h;USER=%u

    # NOTE: you need to set the signature for this backend
    antispam_signature = X-CRM114-CacheID

    #===================
    # spool2dir plugin

    # spam/not-spam spool2dir drop (default unset which will give errors)
    # The first %%lu is replaced by the current time.
    # The second %%lu is replaced by a counter to generate unique names.
    # These two tokens MUST be present in the template! However
    # you can insert any C-style modifier as shown.
    # antispam_spool2dir_spam    = /tmp/spamspool/%%020lu-%u-%%05lus
    # antispam_spool2dir_notspam = /tmp/spamspool/%%020lu-%u-%%05luh
}

crm114 bestie check 🌈: the mailreaver binary defaults to /bin/false (yes, literally that, and there's a commented-out antispam_crm_binary = /usr/share/crm114/mailreaver.crm if you'd rather), extra args and env vars are both semicolon-separated and unset by default, and β€” NOTE β€” you need to set the signature for this backend: antispam_signature = X-CRM114-CacheID.

spool2dir, the spicy one πŸ“: the spam and not-spam drop paths are unset by default, which will give errors. In the template, the first %%lu is replaced by the current time and the second %%lu is replaced by a counter that generates unique names. Those two tokens MUST be present in the template β€” but you can insert any C-style modifier as shown.


🚨 ALLOWING APPENDS? 🚨

okay bestie, listen. You should be careful with allowing APPENDs to SPAM folders. The reason someone might want to allow it is to make not-SPAM β†’ SPAM transitions work with offlineimap. That's the whole point of the feature. πŸ’…

but here's the thing β€” because with APPEND the plugin cannot know the source of the message, multiple bad scenarios can happen:

  1. SPAM β†’ SPAM transitions cannot be recognised and are trained
  2. the same holds for Trash β†’ SPAM transitions

and additionally, because we cannot recognise SPAM β†’ not-SPAM transitions, training good messages will never work with APPEND. periodt. 😭


πŸ‘‘ AUTHORS πŸ‘‘

slay, the whole squad: Johannes Berg, Frank Cusack, Benedikt Boehm, Andreas Schneider. 🫢


and that's the page, bestie! it's ANTISPAM(7), dated 24 March 2012, and it ate, no crumbs. go configure your backend and hydrate. πŸ’–βœ¨πŸ¦‹

πŸ“¦ where this page comes from