OpenSMTPD Mail Filtering
Running an email server that deals competently with spam has always been a difficult, low-reward task. This tutorial will use packages:
p5-Mail-SpamAssassin spampd procmail
spamassassin
is the classification engine,
spampd
connects to the
spamassassin
daemon and forwards the mail to an MTA, and
procmail
writes the messages in the
mbox
format.
SpamAssassin & SpamPD
Filtering mail with OpenSMTPd is most easily accomplished by running a
SpamAssassin proxy that we can forward mail to. The SpamPD relay will add
X-Spam-
headers to each message and forwarded them back to localhost on the port that
we specify
# rc.conf.local pkg_scripts=dkimproxy_out spampd smtpd_flags="" spampd_flags="--port=10025 --relayhost=127.0.0.1:10026 --tagall --log-rules-hit --maxsize=2048"
These
SpamPD options
only need to match the MTA configuration. Setting
--maxsize
allows messages with largish attachments to be processed.
--tagall
and
--log-rules-hit
are not required, but useful for diagnostics.
After routing through spampd each message will contain headers with the evaluation. This is spam that did not reach the configured threshold
X-Spam-Level: *** X-Spam-Status: No, score=3.0 required=4.0 tests=BAD_CREDIT,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HTML_MESSAGE,LOTS_OF_MONEY,MIME_HTML_ONLY, RDNS_DYNAMIC,T_KAM_HTML_FONT_INVALID,URIBL_BLOCKED autolearn=no
And this is a message that was not spam
X-Spam-Level: X-Spam-Status: No, score=-2.2 required=4.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,HTML_MESSAGE,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.1
Procmail
Now that each message is annotated with a score we can optionally route it
using Procmail, which can be configured per user with
$HOME/.procmailrc
or per site with
/etc/procmailrc
.
The following rule will cause suspect mail to be delivered to an mbox named
"spam"
:0: * ^X-Spam-Flag: YES $HOME/mail/spam
If the path to the mailbox does not exist
procmail
will not create the directory, it will ignore the rule.
OpenSMTPD Routing
table aliases file:/etc/mail/aliases listen on localhost port 25 listen on egress inet4 port 25 listen on localhost port 10028 tag DKIM listen on localhost port 10026 tag SCORED action "mbox" mbox alias <aliases> action "relay" relay action relay_dkim relay host smtp://127.0.0.1:10027 action spampd relay host smtp://127.0.0.1:10025 action procmail mda "/usr/local/bin/procmail -f -" match for local action "mbox" match auth from any for domain eradman.com action "mbox" match tag SCORED from any for domain eradman.com action "procmail" match tag DKIM for any action "relay" match for any action "relay_dkim" match auth from any for any action "relay" match from any for domain eradman.com action "spampd"
Incoming mail on port
25
is not tagged, which matches the rule
relay via smtp://127.0.0.1:10025
.
After SpamAssassin grades the mail, SpamPD relays it back to OpenSMTPD on port
10026
where it matches the tag
SCORED
and is handed over to
procmail
for delivery.
This configuration assumes that spam and DKIM signing daemons are up
rc.local
smtpd_flags="" pkg_scripts=dkimproxy_out spamassassin spampd spampd_flags="--port=10025 --relayhost=127.0.0.1:10026 --tagall --log-rules-hit --maxsize=2048"
DKIM Signing
dkimproxy_out.conf
specifies the ports to listen and relay on, along with the domains to sign
# specify what address/port DKIMproxy to listen on listen 127.0.0.1:10027 # specify what address/port DKIMproxy forwards mail to relay 127.0.0.1:10028 # specify what domains DKIMproxy can sign for (comma-separated, no spaces) domain eradman.com # specify what signatures to add signature dkim(c=relaxed) signature domainkeys(c=nofws) # specify location of the private key keyfile /etc/mail/dkim-private.key # specify the selector (i.e. the name of the key record put in DNS) selector selector1
Failure Conditions for SpamPD
1. If
spampd
corrupts it's own bayes database, stop the daemon, and remove everything under
/var/spampd/.spamassassin/
2. If
spampd
encounters trouble creating lockfiles, raise
open-files-cur
in
/etc/login.conf
3. SpamPD can use a significant amount of RAM, provision 500MB for this task
$ ps -U _spampd -o rss | awk '{sum += $1} END {print "RSS for _spamd", sum/1024 "MB"}' RSS for _spamd 598.551MB
4. If
spamassassin
is not yet running
spamd
may panic and begin pegging the server CPU. Start
spamd
late in the boot process