Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

Was fehlt?

Es liegt in der Natur der Sache: Ein Wiki ist niemals fertig. Wir geben uns große Mühe, mit der Entwicklung Schritt zu halten; lassen Supportanfragen direkt in neue Artikel einfließen … aber auch wir sind nicht perfekt. Wenn du hier nicht fündig wirst: Nicht schmollen - Bescheid sagen! Unter hallo@uberspace.de steht dir unser Team gerne bereit. Hand drauf!

mail:maildrop

maildrop

maildrop ist ein Mail Delivery Agent der dazu verwendet wird, eingehende E-Mails nach bestimmten Kriterien zu filtern um sie dann in verschiedene Postfächer zu verteilen oder sie an andere Adressen weiterzuleiten. Gerade bei der Verwendung von IMAP ist maildrop sehr nützlich weil hier schon eine Art Vorsortierung der eingehenden E-Mails in verschiedene Unterordner eines Postfaches erfolgen kann.

Doch maildrop kann eine eingegende E-Mail nicht nur anhand verschiederner Erkennungsmerkmale wie Absenderadresse, Betreff, Inhalt, Empfänger etc. filtern, sondern diese E-Mail auch an Programme wie den Spamassassin, einen Virenfilter oder andere Scripte weiterreichen. Ebenso können auf Grund der Filterregeln auch Headerzeilen hinzugefügt oder abgeändert werden um die E-Mail nachher mit Hilfe des Mailclients (Thunderbird, Evolution, etc.) einfacher zu sortieren oder zu filtern.

Die Konfiguration von maildrop erfolgt in einer Datei, die man dem maildrop-Kommando übergibt. Hier kann dann ein ganzes Regelwerk mit verschiedensten Filterungen erstellt werden, welche maildrop einfach nacheinander abarbeitet.

Auch wenn wir im folgenden eine Reihe von Beispielen geben, sei an dieser Stelle ausdrücklich auf die Dokumentation von maildrop, insbesondere die der Filtersprache verwiesen. maildrop und seine Filtersprache sind durchaus komplex und wir können hier nicht bis ins letzte Detail auf alles eingehen.

Einbindung in qmail

Um maildrop in den Zustellungsprozess einer E-Mail einzubinden, wird das maildrop-Kommando über eine .qmail-Datei aufgerufen. Im einfachsten Fall (nämlich wenn es nur einen einzigen Mailuser gibt, eben die primäre Mailadresse) muss einfach nur die ~/.qmail-Datei angepasst werden, so dass statt der Zustellung ein Maildrop-Aufruf erfolgt.

In den meisten Fällen wird es aber etwas komplexer, nämlich immer dann, wenn es mehrere Mailuser gibt und daher vMailMgr zum Einsatz kommt. In diesen Fällen muss der Maildrop-Aufruf für jede Adresse, bei der maildrop zum Einsatz kommen soll, eingerichtet werden. Dazu legen wir für die jeweiligen User eine .qmail-Datei an. Als Beispiel die .qmail-Datei des Ubernauten klausi für die E-Mail-Adresse info@klausi.amnesia.uberspace.de (/home/klausi/.qmail-info):

|maildrop

Hier wird dem maildrop keine Konfiguration übergeben, womit dann versucht wird, die Datei /home/klausi/.mailfilter aufzurufen.

Wenn du deiner maildrop-Konfiguration einen anderen Namen geben möchtest, z.B. .myfilter, dann musst du diese dem maildrop beim Aufruf übergeben. Da /bin/sh durch eine Pipe | aufgerufen wird, sind auch Systemvariablen nutzbar. Hier also mal ein Beispiel mit $HOME:

|maildrop $HOME/.myfilter

Wie gehen der Einfachheit halber mal davon aus, dass deine Konfiguration den Namen ~/.mailfilter trägt.

Achtung Fallstrick: Die Konfiguration darf nur von dem User lesbar sein, der das maildrop-Kommando ausführt, ansonsten bricht maildrop sofort ab ohne die E-Mail zuzustellen. Aus diesem Grund müssen nach dem Anlegen noch die Zugriffsrechte gesetzt werden:

chmod 600 ~/.mailfilter

Basiskonfiguration

Grundgerüst

Als Grundgerüst sollte die Datei folgendes erhalten:

1. wo ist der Mailordner?

# set default Maildir
MAILDIR="$HOME/Maildir"
 
# check if we're called from a .qmail-EXT instead of .qmail
import EXT
if ( $EXT )
{
  # does a vmailmgr user named $EXT exist?
  # if yes, deliver mail to his Maildir instead
  CHECKMAILDIR = `dumpvuser $EXT | grep '^Directory' | awk '{ print $2 }'`
  if ( $CHECKMAILDIR )
  {
    MAILDIR="$HOME/$CHECKMAILDIR"
  }
}

Mit der Variable $MAILDIR wird festgelegt, wo maildrop das Maildir findet und wie es lautet. Im Beispiel wird überprüft, ob der Aufruf für ein bestimmtes oder das Hauptpostfach erfolgt.

2. Regelwerke

# Hier steht mein Regelwerk
# [ ... ]
# [ ... ]

Regeln, Regeln, Regeln.

3. Alles, was die Regeln überlebt, in den Standardordner aus 1. zustellen

# Standardregel:
to "$MAILDIR"

Die Regel sorgt dafür, das die E-Mail in jedem Fall in das Maildir zugestellt wird, wenn keine vorangegangene Regel gegriffen hat.

Wichtig ist, dass, was immer du für Regeln formulierst, am Ende eine Zustellung steht, also eine to-Anweisung.

Möchtest du ggf. im Verlauf des Filters eine Mail mehrfach zustellen, kannst du auch cc verwenden: Der Unterschied ist, dass nach einer to-Anweisung die Verarbeitung der Filterdatei als abgeschlossen gilt, während nach einer cc-Anweisung weitergemacht wird.

Ordner checken

Wenn du Mails in Ordner wegsortieren willst, ist es ganz sinnvoll zu prüfen, ob die Ordner denn überhaupt schon da sind und wenn nicht, sie anzulegen. Das Anlegen erfolgt, wenn die Filterregeln das erste Mal zum Einsatz kommen, also wenn die nächste Mail eintrifft – das kann natürlich einen Moment dauern.

In dem Beispiel gehen wir mal davon aus, dass es sich um eine Ordnerstruktur für DSPAM und SpamAssasin handelt. Das kann natürlich beliebig angepasst werden.

# check folder structure
`test -d "$MAILDIR/.0 Spamfilter"`
if( $RETURNCODE == 1 )
{
  `maildirmake "$MAILDIR/.0 Spamfilter"`
}
`test -d "$MAILDIR/.0 Spamfilter.als Spam erkannt"`
if( $RETURNCODE == 1 )
{
  `maildirmake "$MAILDIR/.0 Spamfilter.als Spam erkannt"`
}
`test -d "$MAILDIR/.0 Spamfilter.als Spam lernen"`
if( $RETURNCODE == 1 )
{
  `maildirmake "$MAILDIR/.0 Spamfilter.als Spam lernen"`
}
`test -d "$MAILDIR/.0 Spamfilter.als Ham lernen"`
if( $RETURNCODE == 1 )
{
  `maildirmake "$MAILDIR/.0 Spamfilter.als Ham lernen"`
}

Fallstrick: Viele IMAP-Clients abonnieren neue Ordner nicht automatisch, in diesem Fall muss dem Mail-Programm nochmal auf die Sprünge geholfen werden.

SPAM

Bis jetzt haben wir also über eine .qmail-Datei den Zustellprozess dazu veranlasst, maildrop aufzurufen. Diesem wird eine Konfiguration übergeben, die bislang noch nicht wirklich nützlich ist. Also ist es an der Zeit ein Paar Regeln oder Filter einzubauen.

Im Beispiel überlisten wir SPAM mit Hilfe von DSPAM und SpamAssassin, die dann natürlich auch, wie dort beschrieben, eingerichtet werden müssen.

Einbindung von DSPAM

mit xfilter übergeben wir die E-Mail an DSPAM…

# now show the mail to DSPAM
xfilter "/package/host/localhost/dspam/bin/dspam --mode=teft --deliver=innocent,spam --stdout"

… und sortieren sie ggf. weg:

# process SPAM
if (/^X-DSPAM-Result: Spam/)
{
  MAILDIR="$MAILDIR/.0 Spamfilter.als Spam erkannt"
}

Einbindung von Spamassassin

mit xfilter übergeben wir die E-Mail an SpamAssassin…

xfilter "/usr/bin/spamc" 

… zur Bestimmung kann entweder die Headerzeile X-Spam-Flag oder X-Spam-Status

# Filtern nach Spam: yes / no
if ( (/^X-Spam-Flag: YES/:h) || (/^X-Spam-Status: Yes/:h) )

… oder der Spamscore verwendet werden…

# Filtern ab einer bestimmten Spamscore
MAXSPAMSCORE="3"
if ( /^X-Spam-Level: \*{$MAXSPAMSCORE,}$/)

… und sortieren sie ggf. weg:

{
  MAILDIR="$MAILDIR/.0 Spamfilter.als Spam erkannt"
}

Sonstige Filtereien

Filtern nach Inhalt einer E-Mail

maildrop kann natürlich noch mehr. Hier ein Beispiel, in dem über die Filterung einer Headerzeile E-Mails an Hand des Absenders gefiltert und dann in ein definiertes Verzeichnis zugestellt werden (durch die Übergabe von :h greift dieser Filter nur im Header):

# E-Mails von Kollegen in den Ordner "Work" verschieben
if (/^From:.*@mycompany\.com/:h)
{
  MAILDIR="$MAILDIR/.Work"
  `test -d "$MAILDIR"`
  if ( $RETURNCODE == 1 )
    {
      `maildirmake "$MAILDIR"`
    }
  to "$MAILDIR";
}

Hier ein Beispiel für eine Filterung im Body der E-Mail (durch die Übergabe von :b greift dieser Filter nur im Body). Außerdem markieren wir die Mail gleich mal als gelesen.

# Sollte Spam sein:
if ( /cialis pill/:b  || \
     /viagra pill/:b )
{
  MAILDIR="$MAILDIR/.0 Spamfilter.als Spam erkannt"
  # mark as read
  cc "$MAILDIR"; 
  `find "$MAILDIR/new/" -mindepth 1 -maxdepth 1 -type f -printf '%f\0' | xargs -0 -I {} mv "$MAILDIR/new/{}" "$MAILDIR/cur/{}:2,S"`
  exit
}

Header umschreiben und hinzufügen

maildrop kann mittels der xfilter-Anweisung beliebige externe Filter einbinden, wie beispielsweise den Befehl reformail, der unter anderem das Umschreiben und Hinzufügen von Headern ermöglicht. Auch hier ein Beispiel:

# Hinzufügen eines Headers für Filterung im Mailclient
if (/^From:.*susi\@mydomain\.tld/:h)
{
  xfilter "reformail -a'X-Susi: Mail von Susi'"
}

Header entfernen

reformail kann mit -I auch bestehende Header überschreiben oder auch komplett entfernen, nämlich dann, wenn man dem neu zu schreibenden Header keinen Wert mitgibt. Um beispielsweise den von einigen Mailclients standardmäßig gesetzten Header Disposition-Notification-To: zu entfernen, der dem Absender Zustellungsbenachrichtigungen zukommen lässt, kannst du so vorgehen:

# Mehr Privatsphäre, bitte
if (/^Disposition-Notification-To:/:h)
{
  xfilter "reformail -I'Disposition-Notification-To:'"
}

Weiterleitungen

maildrop kann eine E-Mail auch anhand einer Regel an eine andere (auch externe Adresse) weiterleiten:

[...]
to "!me@my-other-domain.tld"
[...]

Oder direkt an mehrere Adressen:

[...]
to "!me@my-other-domain.tld someone@another-domain.tld"
[...]

Für den Fall, dass die E-Mail die weitergeleitet werden soll, von einer Domain stammt, die im DNS einen SPF-Record führt, kann man den Absender vor dem Weiterleiten auch abändern damit der neue Absender z.B. von einer Domain versendet, die auf deinem Uberspace angelegt ist. Damit der Empfänger letztlich noch feststellen kann, von wem die E-Mail ursprünglich stammt, schreibt maildrop die bestehende Headerzeile From: in Old-From: um, bevor der Absender überschrieben wird. Somit geht die Adresse des ursprünglichen Absenders nicht verloren. In der Regel wird diese Information aber nicht vom Mailclient angezeigt. Hier muss der Empfänger sich schon die Header der E-Mail anzeigen lassen.

[...]
xfilter "reformail -i'From: <me@my-local-domain.tld>'"
to "!me@my-remote-domain.tld"
[...]

Und so weiter ...

Natürlich kann man auch komplexe Regeln erstellen. Wer hier tiefer einsteigen möchte, dem ist der Blog von MacFrog zu empfehlen, insbesondere die Artikel Was man mit maildrop alles anstellen kann und Maildrop Revisited. Vielen Dank dafür!

Debugging

Praktisch alle „Seit ich maildrop nutze, bekomme ich überhaupt keine Mails mehr!“-Probleme resultieren daraus, dass deine Filterdatei zu viele Rechte hat. Die Rechte müssen auf 600 gesetzt werden, so wie im Abschnitt Einbindung in qmail beschrieben.

maildrop erwartet zwingend Unix-Zeilenumbrüche (\n). Wenn die Filterdatei mit Windows- (\r\n) oder traditionellen Mac-Zeilenumbrücken (\r) kodiert ist, kann es zu allen möglichen Arten von bizarrem Verhalten kommen. Serverseitig können die Zeilenumbrüche mit dem Befehl dos2unix .mailfilter schnell korrigiert werden.

Logging unter maildrop

Zu Debuggingzwecken kann ein Log geschrieben werden:

logfile "$HOME/mailfilter.log"

Hier sollte dann nach jeder eingegangener E-Mail ein Eintrag im Logfile geschrieben werden, aus dem der Absender, das Datum, der Betreff und das Ziel (nach der Filterung) hervor geht.

Allgemeines Debugging

Es gibt - leider - keinen reinen „lint“-Modus, in dem maildrop einfach nur die Syntax eines Filters checken würde. Du kannst aber für einen reinen Syntaxcheck eine leere Testnachricht auf der Shell direkt an maildrop schicken, wobei dann eventuelle Syntaxfehler direkt auffallen:

[madeleine@neon ~]$ echo | maildrop .mailfilter 
.mailfilter(7): Syntax error.

Auch fehlerhafte Rechte würden so direkt bemängelt:

[madeleine@neon ~]$ echo | maildrop .mailfilter 
maildrop: Cannot have world/group permissions on the filter file - for your own good.

Verwendest du einen Mailfilter für virtuelle Postfächer, der insofern von der Umgebungsvariable $EXT abhängt, die den Namen des Postfachs enthält, in das der Filter die Mail letztlich zustellen soll, kannst du jene Variable direkt mit angeben und dort den Namen des gewünschten vmailmgr-Users nennen:

[madeleine@neon ~]$ echo | EXT=someuser maildrop .mailfilter 

TL;DR

Hier einfach noch einmal ein Beispiel einer maildrop-Konfiguration mit den obigen Beispielen zu SPAM mit erklärenden Kommentaren in der Konfiguration selbst.

DSPAM muss eingerichtet sein und laufen, sonst wird das nichts mit der folgenden Konfiguration!

(/home/klausi/.mailfilter):

MAXSPAMSCORE="3" 
logfile "$HOME/mailfilter.log"
 
# set default Maildir
MAILDIR="$HOME/Maildir"
 
# check if we're called from a .qmail-EXT instead of .qmail
import EXT
if ( $EXT )
{
  # does a vmailmgr user named $EXT exist?
  # if yes, deliver mail to his Maildir instead
  CHECKMAILDIR = `dumpvuser $EXT | grep '^Directory' | awk '{ print $2 }'`
  if ( $CHECKMAILDIR )
  {
    MAILDIR="$HOME/$CHECKMAILDIR"
  }
}
 
# check folder structure
`test -d "$MAILDIR/.0 Spamfilter"`
if( $RETURNCODE == 1 )
{
  `maildirmake "$MAILDIR/.0 Spamfilter"`
}
`test -d "$MAILDIR/.0 Spamfilter.als Spam erkannt"`
if( $RETURNCODE == 1 )
{
  `maildirmake "$MAILDIR/.0 Spamfilter.als Spam erkannt"`
}
`test -d "$MAILDIR/.0 Spamfilter.als Spam lernen"`
if( $RETURNCODE == 1 )
{
  `maildirmake "$MAILDIR/.0 Spamfilter.als Spam lernen"`
}
`test -d "$MAILDIR/.0 Spamfilter.als Ham lernen"`
if( $RETURNCODE == 1 )
{
  `maildirmake "$MAILDIR/.0 Spamfilter.als Ham lernen"`
}
 
# show the mail to SpamAssassin
xfilter "/usr/bin/spamc"
 
# now show the mail to DSPAM
xfilter "/package/host/localhost/dspam/bin/dspam --mode=teft --deliver=innocent,spam --stdout"
 
# process SPAM
if ( /^X-Spam-Level: \*{$MAXSPAMSCORE,}$/ || /^X-DSPAM-Result: Spam/)
{
  MAILDIR="$MAILDIR/.0 Spamfilter.als Spam erkannt"
  # mark as read
  cc "$MAILDIR";
  `find "$MAILDIR/new/" -mindepth 1 -maxdepth 1 -type f -printf '%f\0' | xargs -0 -I {} mv "$MAILDIR/new/{}" "$MAILDIR/cur/{}:2,S"`
  exit
}
 
# and finally, deliver everything that survived our filtering
to "$MAILDIR"
mail/maildrop.txt · Zuletzt geändert 2014/10/12 14:47 von uber