Der Hostingprovider Uberspace betreibt zwei Plattformen, Uberspace 6 basierend auf CentOS 6 und Uberspace 7 basierend auf CentOS 7. Für das Filtern von Mails im Uberspace 6 gibt es eine sehr gute Anleitung im Wiki. Im Uberspace 7 Manual ist das Mailfiltern dokumentiert, allerdings für meinen Geschmack etwas zu knapp.

Filtern mit dem eingebauten Rspamd

Die Doku in “Filtering mails” zeigt, dass der Mailfilter mit uberspace mail spamfilter enable aktiviert wird. Es wird zwar Spam mit einem Score größer 15 abgewiesen, der meiste Müll kommt aber weiterhin durch. Allerdings kann man anhand der eingefügten Mailheader eine weitergehende Filterung vornehmen.

Das Filtern von Mails mittels maildrop und .qmail wird zwar in der Uberspace7-Dokumentation nicht erwähnt, aber es sind alle notwendigen Programme installiert. Man kann also genauso wie im Uberspace 6 Wiki beschrieben, eigene maildrop-Filter erstellen und mittels .qmail einbinden.

Hier die Basisversion eines maildrop-Filters, der das Ergebnis der rspamd-Analyse nutzt, um Spam auszufiltern:

# set Maildir
MAILDIR = "$HOME/Maildir"

# check if we're called from a .qmail-EXT instead of .qmail
import EXT
if ("$EXT" ne "")
{
  # does a vmailmgr user named $EXT exist?
  # if yes, deliver mail to his Maildir instead
  CHECKMAILDIR = `dumpvuser --quiet "$EXT" | sed -n 's/^Directory: *//p'`
  if ("$CHECKMAILDIR" ne "")
  {
    MAILDIR="$HOME/$CHECKMAILDIR"
  }
}

TRASHDIR = "$MAILDIR/.Trash"
SPAMDIR = "$MAILDIR/.Junk"

# check folder structure
`test -d "$SPAMDIR" || maildirmake "$SPAMDIR"`

logfile "$HOME/logs/mailfilter.log"

### spam with high score from rspamd
if (/^X-Rspamd-Score: *([+-]?[0-9.]+)/:h && $MATCH1 >= 7)
{
  log "SPAM: Rspamd score=$MATCH1"
  to "$SPAMDIR"
  #to "$TRASHDIR"
}

# deliver mail
to "$MAILDIR"

Die Verzeichnisse für SPAM und den Papierkorb müssen bei Bedarf angepasst werden. Der Verzeichnisname setzt sich aus einem führenden “.” plus dem IMAP-Namen zusammen.

Dieser Filter prüft den rspamd-Header und bei einem Score größer 7 wird die Mail in den Spamordner verschoben. Man sollte prüfen, ob ausschließlich SPAM aussortiert wird, bei Bedarf muss man den Schwellwert erhöhen. Wenn man sicher ist, dass das System zuverlässig funktioniert, kann man alternativ die Mails auch direkt in den Papierkorb verschieben.

Bei mir wird dadurch ein Großteil des SPAMs aussortiert. Je nach SPAM-Aufkommen ist diese Filterung evtl. schon ausreichend. Falls nicht, muss noch ein lernfähiger Filter hinzugefügt werden.

Statistischer Filter

Ein statistischer Filter lernt durch Rückmeldungen des Benutzers, was SPAM ist und was nicht. Viele Mailclients haben eine entsprechende Funktion eingebaut, so dass diese Filterung nicht unbedingt auf dem Mailserver erfolgen muss. Wenn man allerdings mit mehreren Clients die Mails liest, ist es lästig jeden Client separat zu trainieren.

Zuerst müssen wir ein entsprechendes Programm auswählen. Uberspace 6 bietet dafür DSPAM und SpamAssassin an. DSPAM wird allerdings nicht mehr supportet und der statistische Filter von SpamAssassin ist nicht mehr auf der Höhe der Zeit. Beide Programme sind auch nicht im Uberspace 7 installiert.

Nach etwas Recherche habe ich mich für CRM114 entschieden. Es wurde zwar sehr lange nicht mehr aktualisiert, ist aber weiterhin in vielen Linux-Distributionen präsent. Der Lernalgorithmus ist sehr schnell und effizient, das Programm ist sehr klein und performant.

Installation

Ich baue CRM114 aus der Source und installiere es in das $HOME/crm114 Verzeichnis. Meine Konfigurationsdateien biete ich als fertiges Archiv an, die sind auch für dieses Verzeichnis bestimmt.

Vorsicht: Bestehende Dateien in crm114 werden ohne Nachfrage überschrieben.

mkdir -p ~/crm114
cd ~/crm114
curl -sSL http://crm114.sourceforge.net/tarballs/crm114-20100106-BlameMichelson.src.tar.gz | tar xz
cd crm114-20*
curl -sSL https://laurikari.net/tre/tre-0.8.0.tar.bz2 | tar xj
cd tre*
./configure --prefix "`cd ..; pwd`/tre" --enable-static
make install
cd ..
sed -i 's/^LDFLAGS/#LDFLAGS/' Makefile
sed -i 's|^\([^#].*\)-ltre|\1tre/lib/libtre.a|' Makefile
CFLAGS="-std=gnu89 -Wno-unused-but-set-variable -I tre/include" LDFLAGS="$CFLAGS" make
strip -s crm114 cssdiff cssmerge cssutil osbf-util
cp -p crm114 cssdiff cssmerge cssutil osbf-util ..
cp -p mailfilter.crm maillib.crm mailreaver.crm mailtrainer.crm rewriteutil.crm shuffle.crm ..
chmod 755 ../*.crm
for i in mailfilter.cf blacklist.mfp priolist.mfp rewrites.mfp; do cp -p $i ../$i.example; done
cp -p whitelist.mfp.example ..
cd ..
rm -r crm114-20*

curl -sSL https://www.bernhard-ehlers.de/crm114/crm114-config.tar.gz | tar xz
sh db_init

Hier eine Übersicht meines Archives:

*.cf, *.mfp Meine Konfiguration
cache_cleanup Skript zum Löschen alter Mails aus dem Cache
db_init Erzeugt leere SPAM-Datenbank
learn_maildir Skript zum Trainieren falsch klassifizierter Mails,
basiert auf dspam-learn.uberspace6, dem Uberspace6-Pendant für’s DSPAM-Training.

Konfiguration

Ausführliche Anleitungen gibt’s im CRM114_Mailfilter_HOWTO und im CRM114-Wiki.

Die Konfiguration beschränkt sich hauptsächlich auf mailfilter.cf. Durch die vielen Kommentare sollte sie einfach anpassbar sein. Die weiteren Konfigurationsdateien kann man erst einmal so belassen.

Einbinden in das Mailsystem

Das CRM114-System muss in den maildrop-Filter eingebunden werden. Dazu wird nach dem rspamd-Check die Mail von CRM114 klassifiziert.

#### statistical spam filter
if ($SIZE < 1000000)
{
  xfilter "'$HOME/crm114/crm114' -u '$HOME/crm114' mailreaver.crm --"
  if (/^X-CRM114-Status: *SPAM/:h)
  {
    to "$SPAMDIR"
  }
}

Falsch klassifizierte Mails müssen vom Benutzer in spezielle (von ihm erzeugte) IMAP-Ordner einsortiert werden. Dafür habe ich im Mailprogramm zwei Ordner in der Hauptebene angelegt: “Lerne-HAM” für Mails, die als gut gelernt werden sollen und “Lerne-SPAM” für SPAM-Mails.

  • Erwünschte Mails (HAM), die von CRM114 als SPAM erkannt wurden und in dem Spamordner gelandet sind, sollte der Benutzer in den Posteingang verschieben und anschließend in den “Lerne-HAM”-Ordner kopieren.
  • HAM-Mails, die mit “UNSURE: “ im Betreff markiert wurden, sollten in den “Lerne-HAM”-Ordner kopiert werden.
  • SPAM, der im Posteingang gelandet ist, sollte man einfach in den “Lerne-SPAM”-Ordner verschieben.
  • SPAM-Mails, die als “UNSURE: “ markiert eintreffen, sollte man gleichfalls in den “Lerne-SPAM”-Ordner verschieben.

Mails, die CRM114 korrekt als HAM- oder SPAM-Mails klassifiziert hat, brauchen nicht in diese Lern-Ordner einsortiert werden. Da die Anzahl der fehlerhaft klassifizierten Mails nach der Anfangszeit stark abnimmt, macht der statische Filter dann kaum noch Arbeit.

Das Skript crm114/learn_maildir holt die Mails aus diesen IMAP-Ordnern und trainiert damit CRM114. Die SPAM-Mails werden anschließend gelöscht, HAM-Mails in den Papierkorb verschoben. Falls man versehentlich HAM-Mails in den “Lerne-HAM”-Ordner verschoben und nicht kopiert hat, kann man sie nach dem Duchlaufs des Skripts aus dem Papierkorb zurückholen.

Im nächsten Schritt muss nun crm114/learn_maildir überprüft/angepaßt werden:

  • Wenn man andere Mailordner als Lern-Ordner nutzen möchte, muss man die Variablen HAMDIR und SPAMDIR entsprechend modifizieren.
    Mailordner in der Hauptebene werden als .<Ordnername> eingetragen, Mailordner in einem Unterverzeichnis als .<Hauptordner>.<Ordnername>.
  • Weiterhin sollte man die Variable TRASHDIR prüfen. Sie muss den Verzeichnisnamen des Papierkorbs (mit führendem “.”) enthalten.

Um das learn_maildir-Skript regelmäßig auszuführen, wird es in die crontab (mit crontab -e) eingetragen. Der folgende Eintrag führt learn_maildir alle 20 Minuten aus:

*/20 * * * *	sleep $((RANDOM \% 40 + 10)); crm114/learn_maildir

Zum Trainieren speichert CRM114 alle Mails in einem Cache. Alte Mails sollten zyklisch daraus entfernt werden. Dazu lässt man cache_cleanup per crontab ausführen:

32 4 * * 0,3	crm114/cache_cleanup

Damit nicht alle Aufräumaktionen zur gleichen Zeit auf dem Server starten, sollte die Uhrzeit variiert werden.

Erfahrungen

Anfangs sind die Ergebisse des Filters natürlich sehr schlecht. Das CRM114 lernt aber sehr schnell. Schon nach 20 neu trainierten Mails werden die Ergebnisse besser. Im weiteren Verlauf wird die Anzahl falsch klassifizierter Mails immer geringer. Deshalb halte ich es für unnötig das System vorab zu trainieren. Falls man das aber dennoch möchte, sollte man sich das Beispielskript train.example ansehen.

Log-Dateien verwalten

Um zu verhindern, dass die Logdateien unbegrenzt wachsen, sollten zyklisch neue Logdateien aufgemacht werden. Dafür eignet sich hervorragend logrotate.

Mit dieser Konfiguration in ~/etc/logrotate.conf wird wöchentlich eine neue Mail-Logdatei erstellt. Es werden 4 alte Versionen kompromiert abgelegt, noch ältere Versionen werden gelöscht.

~/logs/mailfilter.log {
    weekly
    missingok
    rotate 4
    compress
    create
}

Nun muss logrotate noch in die crontab eingetragen werden. Die Startzeit sollte man variieren, damit nicht alle Jobs gleichzeitig starten.

21 3 * * *	/usr/sbin/logrotate --state etc/logrotate.state etc/logrotate.conf