265 lines
10 KiB
Markdown
265 lines
10 KiB
Markdown
# 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 MTA’s 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].
|
||
|
||
[Apache SpamAssassin]: https://spamassassin.apache.org
|
||
[Postfix]: https://www.postfix.org
|
||
[spamass-milter]: https://savannah.nongnu.org/projects/spamass-milt
|
||
[Dovecot]: https://dovecot.org
|
||
[Sieve plugin]: https://doc.dovecot.org/configuration_manual/sieve
|
||
|
||
## Installation
|
||
|
||
SpamAssassin Milter is a [Rust] project. It can be installed using Cargo as
|
||
usual:
|
||
|
||
```
|
||
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.61.0.
|
||
|
||
[Rust]: https://www.rust-lang.org
|
||
|
||
## Usage
|
||
|
||
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 <code>inet:<em>host</em>:<em>port</em></code> or
|
||
<code>unix:<em>path</em></code>, 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 man page
|
||
[*spamassassin-milter*(8)]. (You can view the man page without installing by
|
||
passing the file’s 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*(8)]: https://gitlab.com/glts/spamassassin-milter/-/blob/0.3.2/spamassassin-milter.8
|
||
[`spamassassin-milter.service`]: https://gitlab.com/glts/spamassassin-milter/-/blob/0.3.2/spamassassin-milter.service
|
||
|
||
## Configuration
|
||
|
||
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`:
|
||
|
||
```
|
||
--socket=/run/spamassassin/spamd.sock
|
||
```
|
||
|
||
When SpamAssassin reports are disabled, it is recommended to use the `--headers`
|
||
option:
|
||
|
||
```
|
||
--headers
|
||
```
|
||
|
||
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 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:
|
||
|
||
```
|
||
--no-safe-fallback
|
||
```
|
||
|
||
## 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/main.cf`
|
||
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, won’t 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
|
||
SpamAssassin’s `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";
|
||
stop;
|
||
}
|
||
```
|
||
|
||
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’.
|
||
|
||
[Sieve]: http://sieve.info
|
||
[Dovecot]: https://dovecot.org
|
||
[LMTP]: https://doc.dovecot.org/configuration_manual/protocols/lmtp_server
|
||
|
||
## Licence
|
||
|
||
Copyright © 2020–2023 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 https://www.gnu.org/licenses/.
|