SpamAssassin Milter
Go to file
2024-02-20 16:30:00 +01:00
src Fix Clippy warning, update deps 2024-02-20 10:38:52 +01:00
tests Update deps, MSRV 1.65.0 2023-09-25 09:01:17 +02:00
.gitignore Initial commit 2020-01-30 21:27:28 +01:00
.gitlab-ci.yml Replace miltertest tests with indymilter-test 2023-01-18 10:23:21 +01:00
Cargo.lock Fix Clippy warning, update deps 2024-02-20 10:38:52 +01:00
Cargo.toml Fix Clippy warning, update deps 2024-02-20 10:38:52 +01:00 Note MSRV in changelog 2024-02-10 12:16:11 +01:00
LICENSE Initial commit 2020-01-30 21:27:28 +01:00 Note MSRV in changelog 2024-02-10 12:16:11 +01:00
spamassassin-milter.8 Improve man page formatting 2024-02-20 16:30:00 +01:00
spamassassin-milter.service Switch to indymilter 2022-02-21 18:58:24 +01:00

SpamAssassin Milter

SpamAssassin Milter is a milter application that filters email through SpamAssassin server using the spamc client. It is a light-weight component that serves to integrate Apache SpamAssassin with a milter-capable MTA (mail server) such as Postfix. Its task is thus helping combat spam on email sites.

SpamAssassin Milter operates as a milter hooked into the MTAs SMTP protocol handler. It passes incoming messages to SpamAssassin for analysis, and then interprets the response from SpamAssassin and applies suggested changes to the message.

By default, the following modifications are made:

  • Always: Add SpamAssassin headers to the message (headers starting with X-Spam-)
  • Spam only: Rewrite headers Subject From To, if requested
  • Spam only: Replace message body (and rewrite related headers MIME-Version Content-Type, if requested)

Alternatively, messages flagged as spam may be rejected at the SMTP level with an SMTP error reply.

Both SpamAssassin and SpamAssassin Milter provide various configuration options to alter the default behaviour. See below for a discussion of several configuration and integration approaches.

This application can be used as a replacement for spamass-milter; it has a reduced feature set, but it should be sufficient for common mail server setups. SpamAssassin Milter has been used in such a setup on Ubuntu Server together with Postfix, and for delivery Dovecot with LMTP and the Sieve plugin.


SpamAssassin Milter is a Rust project. It can be installed using Cargo as usual. For example, use the following command to install the latest version published on

cargo install --locked spamassassin-milter

SpamAssassin Milter uses the spamc program for communication with SpamAssassin server. By default, /usr/bin/spamc is used as the executable. To override this, set the environment variable SPAMASSASSIN_MILTER_SPAMC to the desired path when building the application.

The minimum supported Rust version is 1.65.0.


Once installed, SpamAssassin Milter can be invoked as spamassassin-milter. spamassassin-milter takes one mandatory argument, namely the listening socket of the milter (the socket to which the MTA will connect). The socket spec should be in one of the formats inet:host:port or unix:path, for a TCP or UNIX domain socket, respectively.

For example, the following invocation starts SpamAssassin Milter on port 3000:

spamassassin-milter inet:localhost:3000

The available options can be glimpsed by passing the -h flag:

spamassassin-milter -h

More detailed information can be found in the provided manual page spamassassin-milter(8). (You can view the manual page without installing by passing the files path to man: man ./spamassassin-milter.8)

Setting up SpamAssassin Milter as a system service is easiest by using the provided systemd service file: Edit spamassassin-milter.service with the desired port, install it in /etc/systemd/system, then enable and start the service. Where necessary, user, group, and umask can also be customised in this file.


SpamAssassin Milter is designed as a light-weight glue application with just a few configuration switches; this is intentional, as the SpamAssassin components are themselves already highly configurable.

SpamAssassin Milter is configured by setting command-line options. All options use sensible defaults that work well with a stock installation of SpamAssassin server (spamd) and client (spamc). You can get started with just picking a socket and things should just work. Some integration options are discussed in subsequent sections.

New users may wish to run SpamAssassin Milter with the --dry-run option before going live. Combined with --verbose, this gives accurate insight into the changes that SpamAssassin Milter would apply.

spamassassin-milter --dry-run --verbose inet:localhost:3000

Integration with SpamAssassin

SpamAssassin Milter must be integrated with two SpamAssassin components: the SpamAssassin server itself, called spamd, which does the actual work, and the SpamAssassin client spamc, which serves as the communication channel between the milter and the server.

SpamAssassin configuration

The main SpamAssassin configuration file is /etc/spamassassin/local.conf. See perldoc Mail::SpamAssassin::Conf for detailed information.

The phrase flagged as spam, which appears throughout this documentation, refers to whether SpamAssassin has marked a message as being spam by adding the header X-Spam-Flag: YES. A message being spam or ham (not spam) is a binary property. The classification threshold can be adjusted by setting required_score as follows:

required_score 9.0

In SpamAssassin Milter, the --reject-spam option will cause messages flagged as spam to be rejected during the SMTP conversation. When rejecting spam in this manner, accepted (not rejected) messages will not have the X-Spam-Flag: YES header; if you need to make a further decision about the message coming through, look at the score in the X-Spam-Level header instead.

By default, SpamAssassin creates reports for messages it recognises as spam. These reports replace the message body, that is, the message body is rewritten to present a report instead of the original message, and the original message is relegated to a MIME attachment. SpamAssassin Milter by default applies reports.

Reports are controlled with the report_safe configuration parameter. Disable reports as follows:

report_safe 0

In addition, body rewriting can also be suppressed on the SpamAssassin Milter side with the --preserve-body option.

SpamAssassin may also rewrite the Subject and other headers, for example, by adding a prefix ***Spam***. This is not done by default, but may be enabled with a setting like the following:

rewrite_header Subject ***SPAM***

SpamAssassin Milter by default applies header rewriting. Header rewriting can be suppressed on the SpamAssassin Milter side with the --preserve-headers option.

spamc configuration

The client program spamc can be configured by passing it command-line options, or preferably, by setting the command-line options in the configuration file /etc/spamassassin/spamc.conf.

By default, spamc will try to reach SpamAssassin server on the dedicated port 783, so that a stock installation of SpamAssassin should work with SpamAssassin Milter without further configuration.

If SpamAssassin server listens on a different port or on a UNIX domain socket instead, set the --port or --socket option as appropriate in spamc.conf:


When SpamAssassin reports are disabled, it is recommended to use the --headers option:


This option is just a shortcut that causes spamd not to transmit the message body back to spamc. (This option obviously only makes sense and should only be used when reports are disabled.)

Finally, a pitfall of spamc deserves highlighting: spamc by default tries to resist failure to such an extent that it will not indicate failure even if it cannot connect to SpamAssassin server at all (apart from warnings logged to syslog)! If it cannot connect to the server, it simply echoes what it received, and so masks the error condition. This behaviour is labelled safe fallback and is perhaps best disabled once the system is set up. Disable safe fallback as follows:


Integration with Postfix

To integrate with Postfix, confirm that the SpamAssassin Milter service is up and running, and then configure its listening socket in /etc/postfix/ as follows:

smtpd_milters = inet:localhost:3000
non_smtpd_milters = $smtpd_milters

After reloading the Postfix configuration, mail will be processed by SpamAssassin Milter.

By default, SpamAssassin Milter will accept, that is, wont check messages coming from local connections (for example, mail sent from the command-line with sendmail), and messages from authenticated senders (for example, mail submitted via a SASL-authenticated channel).

Integration with mail delivery

A further component that may be useful with SpamAssassin Milter is a Sieve-capable mail delivery service. A Sieve script may for example look at SpamAssassins X-Spam- headers in the incoming message, and take action based on those.

As an example, in case Dovecot does mail delivery using LMTP, enable the Sieve plugin for the LMTP protocol, and then set up a global Sieve script that files messages flagged as spam into the Junk folder. That is, test for the header X-Spam-Flag: YES:

require "fileinto";

if header "X-Spam-Flag" "YES" {
  fileinto "Junk";

Alternatively, use the value of the X-Spam-Level header instead. In the example above, the test header :contains "X-Spam-Level" "*****" would file messages with score 5.0 or above into Junk.


Copyright © 20202024 David Bürgin

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see