Aus Linux-Magazin 01/2002

Mail-Filterung mit Procmail

Procmail ist eines jener Programme, die man oft erst auf den zweiten Blick lieben lernt. Wer aber erst mal seine Vorzüge erkannt hat, wird es nicht mehr missen wollen.

Vom einfachen automatischen Abspeichern von E-Mails in die Standard-Inbox bis hin zum Filtern und Sortieren aller eingehenden Mails nach vorgegebenen Kriterien – Procmails Anwendungsmöglichkeiten sind schier endlos. Dieses Tutorial soll den Einstieg in das Mail-Filtern mit Procmail erleichtern.

Wer eine der verbreiteten Linux-Distributionen verwendet, greift wahrscheinlich bereits auf die Dienste von Procmail zurück, ohne es zu wissen. Üblicherweise startet der Mail Transfer Agent (MTA) – meist Sendmail – Procmail für jede eingehende E-Mail automatisch und verwendet es zur Abspeicherung von E-Mails in die Standardmailbox des jeweiligen Benutzers. Man bezeichnet es daher auch als Local Delivery Agent (LDA). Procmail kann aber noch sehr viel weiter reichende Dienste leisten.

Befindet sich in Ihrem Heimatverzeichnis eine Datei ».procmailrc«, so wird sie von Procmail für jede eingehende E-Mail nach einer Vorschrift durchsucht, anhand derer eine weitere Verarbeitung dieser Mail erfolgen kann. Das ermöglicht eine automatische Filterung eingehender E-Mails.

Vor dem Schritt in die Praxis ist jedoch noch ein Wort der Warnung angebracht: Testen Sie eine neue Procmail-Konfiguration gründlich, bevor Sie sie zur Verarbeitung Ihrer E-Mails einsetzen. Das kann beispielsweise unter Verwendung eines eigens für diesen Test eingerichteten Benutzer-Accounts geschehen. Procmail ist ein sehr mächtiges Werkzeug und erleichtert die Arbeit erheblich. Umgekehrt kann eine fehlerhafte Verarbeitungsvorschrift aber auch leicht alle eingehenden Mails in eine falsche Mailbox abspeichern oder sogar ins Datennirwana schicken.

Procmail und reguläre Ausdrücke

Procmail umschließt die Funktionalität von Egrep, eines Programms, mit dem das Durchsuchen von Texten nach bestimmten Suchbegriffen, den regulären Ausdrücken, möglich ist (siehe Kasten “Reguläre Ausdrücke”). Eine ».procmailrc« besteht im einfachsten Fall aus einer Reihe von Rezepten. Ein Rezept hat formal den folgenden Aufbau (eine eckige Klammer [] signalisiert einen optionalen Teil):

:0 [flags] [ : [locallockfile] ]
[* ein Suchmuster]
[* ein Suchmuster]
...
eine Handlungsanweisung

Ein Rezept beginnt stets mit »:0«. Optional folgen unterschiedliche Flags (siehe Tabelle 1). Es folgt eine beliebige Anzahl von Suchbegriffen, dargestellt durch reguläre Ausdrücke. Jeder neue Suchbegriff wird durch ein Sternchen (*) eingeleitet und muss in einer eigenen Zeile stehen. Das Sternchen signalisiert nur den Beginn eines neuen Suchbegriffs und wird nicht zu ihm gezählt.

Ein Rezept wird durch eine Handlungsanweisung abgeschlossen. Steht in dieser Zeile nur ein einzelner Name, bewirkt die Handlungsanweisung das Abspeichern der E-Mail in einen Mail-Folder mit diesem Namen. Das ist sicherlich die am häufigsten vorkommende Regel von Procmail.

Fehlen in einem Rezept die Suchbegriffe oder existiert nur ein leerer Ausdruck (signalisiert durch ein einzelnes Sternchen in einer eigenen Zeile), wird die Handlungsanweisung in jedem Fall ausgeführt. Sind in einem Rezept mehrere Suchbegriffe enthalten, wird nacheinander nach allen Begriffen in der E-Mail gesucht. Nur wenn alle gefunden wurden, wird die Handlungsanweisung ausgeführt (UND-Verknüpfung).

Werden ein oder mehrere Suchbegriffe nicht gefunden, springt Procmail zum nächsten Rezept in ».procmailrc«. Wurden alle Suchbegriffe eines Rezepts in einer Mail gefunden, bricht die weitere Abarbeitung der ».procmailrc« normalerweise ab. Eine passende ODER-Variante gibt es nicht, man muss sie nach der booleschen Algebra mit Hilfe negierter UND-Terme darstellen.

Neben Rezepten können in einer ».procmailrc« noch Environment- und Steuervariablen sowie Kommentare vorkommen. Ein Kommentar wird durch eine Raute (#) eingeleitet.

Tabelle 1: Flags für Procmail-Regeln

Tabelle 1: Flags für Procmail-Regeln

Eine einfache ».procmailrc«

Nachdem wir den theoretischen Aufbau einer ».procmailrc« kennen, lässt sich eine einfache Version dieser Datei erstellen. Stellen Sie zunächst sicher, dass diese Datei nicht bereits in Ihrem Heimatverzeichnis existiert, und fertigen falls erforderlich ein Backup an.

Da es sich um eine reine Ascii-Datei handelt, kann man jeden beliebigen Texteditor benutzen. Eine sehr einfache ».procmailrc« kann so aussehen:

VERBOSE=yes
LOGABSTRACT=all
MAILDIR=$HOME/Mail
PROCMAILDIR=$HOME/.Procmail
LOGFILE=$PROCMAILDIR/log

:0
*
.incoming

Die im Beispiel angegebenen Verzeichnisse »$HOME/Mail« und »$HOME/ .Procmail« müssen vorher bereits existieren; Procmail legt sie nicht selbsttätig an. Befindet sich eine ».procmailrc« mit diesem Inhalt in Ihrem Heimatverzeichnis, werden alle eingehenden E-Mails automatisch in die Datei »$HOME/Mail/ .incoming« abgespeichert.

Die Werte der Variablen »VERBOSE« und »LOGABSTRACT« sorgen dafür, dass bei jeder Abarbeitung der ».procmailrc« ausführliche Informationen über den Verlauf der Abarbeitung in der »$HOME/ .Procmail/log«-Datei (angegeben durch die Variable »LOGFILE«) abgespeichert werden. Wollen Sie die Generierung dieser Informationen unterbinden, setzen Sie »VERBOSE« auf »no« und kommentieren »LOGABSTRACT« aus (mit Hilfe der Raute). MAILDIR gibt das Verzeichnis an, in dem Mails abgespeichert werden sollen.

Alle bisher besprochenen Variablen sind interne Steuervariablen von Procmail. Im Gegensatz dazu ist »PROCMAILDIR« eine von uns definierte freie Variable, die wir der Übersichtlichkeit und einfacheren Wartbarkeit der ».procmailrc« halber verwenden. In unserem Beispiel gibt diese Variable einfach ein Verzeichnis an, das wir zum Sammeln von im Zusammenhang mit Procmail relevanten Dateien verwenden.

Die Handlungsanweisung besteht in unserem einfachen Beispiel also nur aus einem einzelnen Namen. Der wird von Procmail als Name der Mailbox interpretiert, in die Mails abgespeichert werden sollen. Ist die Variable »MAILDIR« wie in unserem Beispiel definiert, ist keine Angabe eines Verzeichnisses für die Abspeicherung der Mail respektive die Erstellung eines Mail-Folders durch Procmail mehr notwendig.

Anpassung des Mailers

Beachten Sie, dass Sie den Mail-Client umkonfigurieren müssen, wenn Sie unsere ».procmailrc« verwenden wollen. Alle eingehenden Mails werden ja jetzt in der Datei »$HOME/Mail/.incoming« gespeichert. Verwenden Sie zum Beispiel Pine, geht das im Menü »Setup | Config | inbox-path«. Mutt erwartet dagegen einen besonderen Eintrag in der Datei ».muttrc«:

set spoolfile=~/Mail/.incoming

Filtern von Mails

Wir gehen im Folgenden von einer typischen Situation aus und nehmen an, dass Sie eine stark frequentierte Mailingliste abonniert haben. Sie haben sich aus diesem Grund entschieden, alle Mails dieser Liste von Procmail direkt in einen eigenen Mail-Folder abspeichern zu lassen, den Sie nur gelegentlich anschauen möchten. Um ein solches Konzept zu verwirklichen, müssen Sie nach einem eindeutigen Merkmal im Header der Mails suchen. Haben Sie es gefunden, ist ein regulären Ausdruck zu generieren, der dieses Merkmal definiert.

Im Folgenden als Beispiel ein Teil des Mailheaders aus einer stark frequentierten Mailingliste:

X-Mailinglist: linux
Delivered-To: mailing list linux@zzzz1.com
Received: (qmail 29 invoked from network);
        17 Apr 2000 18:44:37 -0000
Delivered-To: linux@zzzz1.com
Reply-To: <xxxx@xxxx.xxxx1.com>
From: "xxxx" <xxxx@xxxx.xxxx1.com>
To: "Another User" <yyyy@yyyy1.com>
Cc: "Linux List" <linux@zzzz1.com>
Date: Mon, 17 Apr 2000 15:45:50 -0300

Zunächst fällt auf, dass wir uns nicht unbedingt darauf verlassen können, dass eine Mail direkt an eine Mailingliste geschickt wird. Eine Mail könnte etwa auch per CC an diese Liste verschickt werden.

Diese Möglichkeiten zum Filtern von Mails aus der Liste bieten sich an: Die Mailingliste wird fast immer direkt adressiert oder zumindest im CC einer Mail sein. Der folgende Suchbegriff wird deshalb auf die meisten Mails aus der Liste passen:

^(To:|Cc:).*linux@zzzz1.com

Diese Zeile passt auf Zeilen, die entweder mit einem »To:« oder einem »Cc:« beginnen und in denen zusätzlich an be-liebiger Stelle die Zeichenkette »linux@zzzz1.com« vorkommt. Mit Hilfe des Makros »^TO« lässt sich dies noch kürzer fassen :

^TO.*linux@zzzz1.com

Diese beiden Suchbegriffe werden allerdings keine Mails abfangen, in denen die Mailingliste nur im BCC enthalten war, in der der Empfänger also nicht im Mailheader auftaucht.

Ein unveränderliches Merkmal des genannten Mailheaders scheint jedoch die Zeile »X-Mailinglist: linux« zu sein. Mit ihr sollten wir alle Mails von dieser Liste aus dem Mail-Strom herausfiltern können. In unsere ».procmailrc« fügen wir deshalb vor dem letzten Rezept noch ein neues Rezept ein:

:0
* ^X-Mailinglist: linux
linux-liste

Mit diesem einfachen Rezept wird in eingehenden Mails nach dem Vorkommen einer Zeile gesucht, die mit »X-Mailinglist:« beginnt, gefolgt von »linux«. Solche Mails werden dann im Mail-Folder »$MAILDIR/linux-liste« abgespeichert. Zeilen der Art

X-Mailinglist: announce-linux

ignoriert diese Regel hingegen.

Reguläre Ausdrücke

Reguläre Ausdrücke

Mehr als ein Suchbegriff – Weiterleitung

Im nächsten Schritt sollen alle Mails, die aus unserer Mailingliste stammen und sich mit dem Thema Procmail beschäftigen, an eine dritte Person mit der Adresse hans@wwww1.com weitergeleitet sowie lokal eine Kopie davon angefertigt werden. Das Rezept verändern wir hierfür folgendermaßen:

:0
* ^X-Mailinglist: linux
* ^Subject:.*procmail
{
    :0 c
    linux-liste

    :0
    ! hans@wwww1.com
}

Nun haben wir zwei Suchbegriffe im Beispiel. Es werden nur solche Mails akzeptiert, die aus unserer Mailingliste stammen und im Subject den Begriff »procmail« enthalten. Findet die Regel beide Suchbegriffe in einer Mail, dann legt sie die Mail zunächst in »$MAILDIR/linux-liste« ab. Das Flag »c« (für Copy) erzeugt nun eine Kopie, die zur nächsten Unterregel weitergeleitet wird. Hier wird diese Kopie – das Ausrufezeichen sorgt dafür – an »hans@wwww1 .com« verschickt.

Eine weitere Besonderheit: In diesem Rezept sind zwei Handlungsanweisungen enthalten. Die geschweiften Klammern ermöglichen es, mehrere Anweisungen zu bündeln, die beim Zutreffen der ersten beiden Suchbegriffe (»X-Mailinglist« und »Subject«) abgearbeitet werden.

Procmail kann Mails auch an externe Programme zur weiteren Bearbeitung weiterleiten. Hierzu steht das Pipe-Zeichen (|) zur Verfügung:

:0
* ^Subject.*foobar
| formail -r -k | sendmail -t

Auf diese Weise lässt sich beispielsweise eine automatische Antwort versenden, wenn eine Mail ein bestimmtes Muster enthält. Formail ist Bestandteil des Procmail-Pakets – es ist in der Lage, automatisch einen Reply-Header zu erzeugen (Option »-r«), Header zu modifizieren, zu löschen oder hinzuzufügen oder Mail-Folder im Mbox-Format wieder in Einzelmails zu zerlegen.

Wegwerfen unerwünschter Mail

Wenn Sie in der unglücklichen Situation sind, immer wieder lästige Werbemails (UCE, Spam) zu erhalten, können Sie diese relativ einfach automatisch entsorgen. Enthält das Subject der Mails zum Beispiel stets das Wort Spam, dann kann die folgende Regel diese Mails löschen:

:0
 * ^Subject:.*Spam
/dev/null

Leider sind die meisten Werbetreibenden im Internet nicht annähernd so nett, ihre Werbung so zu kennzeichnen, man muss in die Lösung dieses Problems also etwas mehr Denkarbeit investieren (siehe Kasten “Kampf dem Spam”).

Performance-Verbesserungen

Wenn Sie mehrere hundert Mails am Tag erhalten, sollten Sie darauf achten, Ihre ».procmailrc« effizient zu gestalten. Die Grundregel ist, häufig verwendete Regeln an den Anfang der Konfigurationsdatei zu stellen, sonst werden zuerst alle anderen Regeln durchlaufen.

Mit Hilfe des Programms Mailstat können Sie sich aus den Debugging-Informationen, die Sie durch das Setzen der Variablen »VERBOSE« und »LOGABSTRACT« erhalten haben, eine Statistik generieren. Das ist besonders bei einer neu erstellten ».procmailrc« zum Auffinden von Fehlern hilfreich. Rufen Sie dazu Mailstat einfach mit dem Namen des Logfiles auf, in unserem Fall:

mailstat $HOME/.Procmail/log

Es ist auch möglich, externe Dateien in die ».procmailrc« einzubinden. Das wird dann hilfreich, wenn die ».procmailrc« im Laufe der Zeit stark gewachsen ist und übersichtlicher gestaltet werden soll. Um diesen Mechanismus zu nutzen, speichern Sie einfach eine Regel in einer eigenen Datei ab, etwa »$HOME/ .Procmail/linux-liste.rc«. Löschen Sie dann die alte Regel in der ».procmailrc« und fügen an ihrer Stelle die folgende Zeile hinzu:

INCLUDERC=$PROCMAILDIR/linux-liste.rc

Weiterführende Informationen finden sich unter anderem auf der Procmail- Homepage[1] und in der zugehörigen FAQ[2]. (hmi)

Kampf dem Spam!

Ein besonders nützliches Beispiel: die Bekämpfung von unerwünschter Werbung, eine Regel für Abwesenheit und der Einbau schwarzer Listen …

Die Philosophie einer solchen ».procmailrc« geht davon aus, dass jeder Mail-Versender böse ist – im Umgang mit Spam nicht die schlechteste Annahme. Die Anregung zu dieser Vorgehensweise gab Lars Wirzenius vor Jahren auf seiner Homepage. Der gezeigte Regelsatz ist hinreichend paranoid, um Schutz vor mindestens 90 Prozent des Spams zu bieten. Die Beispiele sind aus Platzgründen stark vereinfacht und garantiert nicht ohne Anpassungen ablauffähig.

Zunächst setzt die ».procmailrc« einige nützliche Variablen:

VERBOSE=yes
MAILDIR=/home/hm/Mail
PROCMAILDIR=/home/hm/.procmail
OFFADDR=hm@webmail.de
SENDMAIL=/usr/sbin/sendmail

»OFFADDR« ist hierbei die offizielle Adresse für ein- und ausgehende Mails.

Mit Hilfe zweier Dateien (»blacklist« und »whitelist«) wird die Mail vorgefiltert – Mail von Absendern, die in der Blacklist stehen, wird ohne Warnung weggeworfen, Mail von Whitelist-Absendern immer akzeptiert. Beide Listen muss man von Hand editieren, aber man kann sich auch Mechanismen zur Teilautomatisierung einfallen lassen. In beiden Dateien dürfen Egrep-fähige reguläre Ausdrücke stehen, ein Adresstemplate pro Zeile.

BLACKLIST=$PROCMAILDIR/blacklist
WHITELIST=$PROCMAILDIR/whitelist

Nun noch ein paar Einstellungen für die Vacation-Regel:

VACATION=$PROCMAILDIR/vacation.txt VACATIONDB=$PROCMAILDIR/vacation.db

Logging erfolgt in je eine Logdatei pro Tag:

LOGFILE=$PROCMAILDIR/`date +%d%m%y`.log
LOGABSTRACT=all

Schließlich ein Schalter fürs Debuggen – in diesem Fall landen Kopien aller eingehenden Mails in einem Folder namens »mail-backup«. Auf diese Weise geht garantiert keine Mail wegen einer falschen Regel verloren.

DEBUG=yes
:0 Wc:
* ? test x$DEBUG = xyes
$MAILDIR/mail-backup

Es reicht, Mails nur einmal zu bekommen und Dubletten wegzuwerfen. »formail« schaut dazu nach, ob die Message-ID der Mail schon in der 32 KByte großen Cache-Datei steht, und gibt bei einer Übereinstimmung den Wert »wahr« zurück. Andernfalls schreibt es die neue Message-ID in die Cache-Datei:

:0 Wh: $PROCMAILDIR/msgid.lock
|formail -D 32768 $PROCMAILDIR/msgid.cache
/dev/null

Blacklist-Mail wegwerfen: Wie zu sehen ist, kann Procmail den Exit-Code externer Programme für die Wahr-falsch-Unterscheidung nutzen:

:0 Wi
| (formail -x from: -x sender: -x to: | U
   grep -iq -f $BLACKLIST)
/dev/null

An dieser Stelle kann man nun diverse Spezialfälle erledigen, beispielsweise Mailinglisten oder bestimmte administrative Systemnachrichten ausfiltern.

Jetzt ist alle Mail, die von Listen et cetera kommt, gefiltert, es verbleibt nur persönliche Mail. Wir können also untersuchen, ob Mails überhaupt an uns adressiert sind, und – falls nicht – wegwerfen. Auf diese Weise wird man Spam los, der an Fantasie-Adressen wie friend@public.com gerichtet ist.

:0 W
* !$ ^TO$OFFADDR
/dev/null

Absender aus der Whitelist lassen wir durch und verarbeiten die Mail weiter (Vacation-Regel). Falls die Datei »vacation.txt« existiert, greift die Regel automatisch, so dass man im Falle einer Abwesenheit nicht die ».procmailrc« ändern muss. Eine Abwesenheitsnachricht wird wegen des Tests auf die »VACATIONDB« nur einmal pro Absender verschickt, es sei denn, die DB-Datei läuft irgendwann über und alte Einträge fliegen aus.

Der Header »X-Loop« vermeidet Mail-Schleifen. Die Regel erzeugt einen Autoreply-Header, hängt die eigentliche Nachricht an und schickt das Ergebnis schließlich an Sendmail weiter.

01 :0 Whic
02 | (formail -x from: -x sender: | U
03    egrep -iq -f $WHITELIST)
04 
05 :0 a
06 {
07  :0 Whc
08  * !$ ^X-Loop: $OFFADDR
09  * ! ^Precedence:.*
10  * ? test -f $VACATION
11  {
12     :0 c: vacation.lock
13     | formail -r -D 8192 $VACATIONDB
14 
15     :0 eh
16      | (formail -r -A"From: $OFFADDR" U
17           -A"X-Loop: $OFFADDR" U
18           -A"Precedence: bulk"
19         cat $VACATION) | $SENDMAIL -t
20 
21   }
22 
23   :0 W: inbox.lock
24   $DEFAULT
25 }

Lars Wirzenius schlug in seinem Beispiel noch weitere Maßnahmen vor – so stand auf seiner Webseite ein Passwort, bei dessen Verwendung im Subject die Mail immer akzeptiert wird. Spam lässt sich auf diese Weise ebenfalls wirkungsvoll wegfiltern. Die Realisierung sei allerdings dem geneigten Leser überlassen – als kleine Übung. :-)

Infos

[1] Procmail: [http://www.procmail.org/]

[2] Procmail-FAQ: [http://www.ling.helsinki.fi/users/reriksso/procmail/mini-faq.html]

Der Autor

Rüdiger Berlich war von 1998 bis 2001 für verschiedene Tochterfirmen der SuSE Linux AG tätig und arbeitet heute in den Bereichen Linux-Clustering und GRID-Computing. Er beschäftigt sich seit 1992 mit Linux.

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben