Maildienste (Exim4, Cyrus und Sieve)

Einleitung

E-Mail ist nach dem WWW der meistgenutze Dienst des Internets. Es gibt eine Vielzahl von Mailprogrammen, auf die hier aber nicht näher eingegangen werden soll. Vielmehr soll hier eine Möglichkeit vorgestellt werden, die es ermöglicht, seine Mails auf einem Server-Rechner zu verwalten und von jedem daran angeschlossenen Client-Rechner aus die selbe Ordnerstruktur vorzufinden. Das Stichwort hierfür lautet: IMAP, das Internet Mail Access Protocol.

Es folgt eine Beschreibung über den IMAP-Server Cyrus 2.1, das Zusammenspiel mit dem Mailserver Exim 4. Zusätzlich wird die Filterung der Mails direkt auf dem Server stattfinden, so dass man nicht in jedem verwendeten E-Mailprogramm erneut seine Filterregeln anlegen muss. Teilweise kann diese Filterung auch mit dem E-Mailprogramm eingerichtet werden, allerdings benutze und kenne ich momentan keines, das diese Funktion unterstützt. :rolleyes:

« zurück (Gesammelte Anleitungen)

Inhalt

IMAP Server Cyrus einrichten

Das Internet Mail Access Protocol (IMAP) erlaubt die Verwaltung von Mails direkt auf dem Server, d. h. man kann mit einem beliebigen Mailprogramm, das IMAP unterstützt, auf den Server zugreifen und findet dann immer die gleiche Ordnerstruktur und Mails vor. Das macht einen einerseits unabhängig von dem Mailprogramm an sich und die Mails werden zentral abgelegt, was wiederum Vorteile für ein Backup bringt. Es ist mit Cyrus sogar möglich, die Mails serverseitig zu filtern, d. h. man muss nicht mal seine Filterregeln (z. B. bestimmte Absender in dafür vorgesehene Ordner verschieben) doppelt und dreifach anlegen. Die Lösung nennt sich Sieve und wird weiter unten beschrieben.

Imapd Konfiguration

Hier die sichere Konfiguration für Cyrus, wie man sie hundertfach auch anderswo finden kann. ;-)

Es gibt zwei verschiedene Konfigurationsdateien für den IMAP-Server. Die eine soll für den rein am Server lokal zur Verfügung gestellten Server gelten und eine für die Verbindung aus dem lokalen Netz. Der Unterschied besteht lediglich in der Restriktion, dass nur für direkt auf dem Serverrechner (localhost) mit dem IMAP-Dienst erstellte Verbindungen einen Admin-Zugang zulassen. Hier die entsprechende Datei /etc/imapd-local.conf:

# Datei /etc/imapd-local.conf
[...]
# Der folgende Eintrag bewirkt, dass die Ordner auf gleicher Ebene mit
# INBOX sind, ansonsten wären es Unterordner von INBOX
altnamespace: yes
# Will man die Sonderzeichen (z. B. / und .) für seine Ordnernamen kann
# man den folgenden Wert auf yes
unixhierarchysep: no
# Admin ist lokal (localhost) zugelassen
admins: cyrus
# keine Gäste!
allowanonymouslogin: no
[...]
# Wenn man Heimverzeichnisse auf dem Server hat, kann man den folgenden
# Wert auch auf yes stellen. In diesem Fall würden die Sieve-Skripte
# dann unter ${HOME}/.sieve abgelegt statt unter /var/spool/sieve
sieveusehomedir: false
sievedir: /var/spool/sieve
[...]
##
## KEEP THESE IN SYNC WITH cyrus.conf
##
lmtpsocket: /var/run/cyrus/socket/lmtp
idlesocket: /var/run/cyrus/socket/idle
notifysocket: /var/run/cyrus/socket/notify

Der einzige Unterschied zu der Datei /etc/imapd.conf ist, dass dort die admin-Zeile auskommentiert ist.

Cyrus Konfiguration

Die Dateien werden nun für die Konfiguration des IMAP-Servers über die Hauptkonfigurationsdatei /etc/cyrus.conf angesprochen:

# Datei /etc/cyrus.conf
START {
  [...]
}
SERVICES {
  # lokales Netz (verwendet standardmäßig die Datei /etc/imapd.conf)
  imap            cmd="imapd -U 30" listen="192.168.1.1:imap" prefork=0 maxchild=100
  # localhost
  imaplocal       cmd="imapd -C /etc/imapd-local.conf -U 30" listen="127.0.0.1:imap" prefork=0 maxchild=100
  # das Gleiche für SSL (Verschlüsselte Verbindungen)
  imaps           cmd="imapd -s -U 30" listen="192.168.1.1:imaps" prefork=0 maxchild=100
  imapslocal      cmd="imapd -C /etc/imapd-local.conf -s -U 30" listen="127.0.0.1:imaps" prefork=0 maxchild=100
  [...]
  # At least one form of LMTP is required for delivery
  # (you must keep the Unix socket name in sync with imap.conf)
  #lmtp           cmd="lmtpd" listen="localhost:lmtp" prefork=0 maxchild=20
  lmtpunix        cmd="lmtpd" listen="/var/run/cyrus/socket/lmtp" prefork=0 maxchild=100
  # ----------------------------------------------
  # lokales Netz (verwendet standardmäßig die Datei /etc/imapd.conf)
  sieve           cmd="timsieved" listen="192.168.1.1:sieve" prefork=0 maxchild=100
  # localhost
  sievelocal      cmd="timsieved -C /etc/imapd-local.conf" listen="127.0.0.1:sieve" prefork=0 maxchild=100
  [...]
}
EVENTS {
  [...]
}

Mit diesen Einstellungen lauscht der IMAP-Server nun auf den folgenden Adressen:

  • 127.0.0.1, Port 143 (IMAP auf localhost)
  • 127.0.0.1, Port 993 (IMAP over SSL auf localhost)
  • 192.168.1.1, Port 143 (IMAP zum lokalen Netzwerk)
  • 192.168.1.1, Port 993 (IMAP over SSL zum lokalen Netzwerk)

Wenn man sich an dem IMAP-Server nicht anmelden kann muss er nicht mal mehr auf localhost (127.0.0.1) lauschen. Die Adresse 127.0.0.1 ist aber nicht von Außen sichtbar oder ansprechbar sondern wird nur rechnerintern verwendet. Somit ist ein Admin-Zugang auf Cyrus nur möglich, wenn man den IMAP-Server direkt vom Serverrechner aus anspricht.

« nach oben

MTA Exim4 mit Smarthost und Authentisierung einrichten

Wenn man einen Provider hat, der einem einen Smarthost für den Mailversand zur Verfügung stellt, kann man diesen gut mit Exim4 benutzen. Die meisten Provider haben inzwischen auf SMTP-auth (Authentifizierung vor der Annahme von Mail) umgestellt, damit ihre Server nicht von Spammern missbraucht werden.

Ferner wäre es schön, wenn der oben beschriebene Cyrus mit eingebunden wird, damit eingehende Mails direkt auf dem IMAP-Server landen.

Smarthost und SMTP-auth einrichten

Unter Debian gibt es bei der Installation von Exim4 die Möglichkeit, die Konfigurationsdatei in viele kleine Dateien zu splitten und durch das Skript update-exim4.conf bei Änderungen in diesen Dateien zu aktualisieren. Sollte dieses Splitting bei der Installation verpasst worden sein, kann es durch ein

# dpkg-reconfigure exim4-config

nachgeholt werden. Hierbei kann man gleich die Konfiguration über den Smarthost wählen und den Servernamen eintragen. Für die Authentisierung ist dann nur noch ein Eintrag in der Datei /etc/exim4/passwd.client nötig:

Servername:Benutzername:Passwort

Der Servername kann auch einfach nur * sein. In diesem Fall wird dann für jeden Smarthost der Benutzername und das Passwort verwendet.

Lokale Mail an Cyrus weiterleiten

Als nächstes wäre es schön, wenn man z. B. auch die lokal zugestellten Mails (meistens vom System) zentral abfängt und mit Cyrus ablegt. Normalerweise werden Mails an root standardmäßig an den normalen Hauptbenutzer weitergeleitet. Diese Mails dümpeln dann in lokalen Postfächern unter /var/mail/username vor sich hin, sofern man dieses nicht mit seinem Mailprogramm abfrägt.

Damit Exim die Mails via Cyrus zustellt, benötigt man eine neue Steuerungsdatei im Verzeichnis /etc/exim4/conf.d/transport namens 30_exim4-config_cyrus_deliver mit folgendem Inhalt:

# Datei /etc/exim4/conf.d/transport/30_exim4-config_cyrus_deliver
#
# Cyrus Konfiguration aus /usr/share/doc/cyrus21-imapd/README-exim
#
cyrus_delivery:
  driver = lmtp
  socket = /var/run/cyrus/socket/lmtp
  batch_max = 100
  group = mail
Cyrus nimmt keine Mails mit NUL-Zeichen an

Cyrus hat die Angewohnheit Mails nicht anzunehmen, die nicht den Standards aus RFC822 und RFC2822 gerecht werden. An für sich ist das eine gute Sache, da es sich in fast allen Fällen bei solchen Mails um Spam oder Viren (Würmer) handelt. Sollte man aber auch normale Mails mit NUL-Zeichen erhalten, kann man diese vor der Übergabe an Cyrus über einen Filter entfernen:

# Datei /etc/exim4/conf.d/transport/30_exim4-config_cyrus_deliver
#
# Cyrus Konfiguration aus /usr/share/doc/cyrus21-imapd/README-exim
#
cyrus_delivery:
  transport_filter = /usr/bin/tr -d '\000'
  driver = lmtp
  socket = /var/run/cyrus/socket/lmtp
  batch_max = 100
  group = mail

Damit ist die Grundlage gelegt. Es wird ein neuer Transport namens cyrus_delivery angelegt, der die eingehenden Mails via Pipe (lmtp) an Cyrus weiterleitet. Jetzt muss dieser Transport noch bekannt gemacht werden.

Konfigurationsdatei für den Mailserver

Dies geschieht über die Konfigurationsdatei /etc/exim4/update-exim4.conf.conf.

Hinweis
Das doppelte .conf am Ende ist kein Tippfehler, denn das Update-Skript heißt update-exim4.conf und seine Konfigurationsdatei hat demzufolge den Namen update-exim4.conf.conf:

# /etc/exim4/update-exim4.conf.conf
#
# Edit this file and /etc/mailname by hand and execute update-exim4.conf
# yourself or use 'dpkg-reconfigure exim4-config'
dc_eximconfig_configtype='smarthost'
dc_other_hostnames='hostname_of_this_machine'
dc_local_interfaces='127.0.0.1:192.168.1.1'
dc_readhost=''
dc_relay_domains=''
dc_minimaldns='false'
dc_relay_nets='192.168.1.0/24'
dc_smarthost='your_providers_smarthost'
CFILEMODE='644'
dc_use_split_config='true'
dc_hide_mailname='false'
dc_localdelivery='cyrus_delivery'
dc_mailname_in_oh='true'

Die Daten an den blauen Stellen müssen angepasst werden, d. h. die richtigen IP-Adressen und die Netzwerkadresse eingetragen und für die Variable dc_other_hostnames durch Doppelpunkt getrennt alle Hostnamen eintragen, für die lokale Mail angenommen werden soll (sprich: für die der Mailserver wiederum als Smarthost fungiert). Eventuell ist es noch sinnvoll, die Variable dc_minimaldns auf true zu setzen, falls es sich um ein System handelt, dass sich nur bei Bedarf ins Internet einwählt und somit nicht ständig eine Verbindung zu einem Nameserver hat.

Anschließend die Konfiguration durch Ausführen des Skriptes update-exim4.conf übernehmen.

Konfigurationsdatei für die Satelliten

Auf den anderen Rechnern sollte in der Variable dc_readhost außerdem der Hostname des Mailservers stehen, damit die Systemmails dieser Systeme auch an den IMAP-Server weitergeschickt werden. Die Konfiguration der Satelliten sieht dann folgendermaßen aus:

# /etc/exim4/update-exim4.conf.conf
#
# Edit this file and /etc/mailname by hand and execute update-exim4.conf
# yourself or use 'dpkg-reconfigure exim4-config'
dc_eximconfig_configtype='satellite'
dc_other_hostnames='this_machines_hostname'
dc_local_interfaces='127.0.0.1'
dc_readhost='your_imap_servers_hostname'
dc_relay_domains=''
dc_minimaldns='true'
dc_relay_nets=''
dc_smarthost='your_imap_servers_hostname'
CFILEMODE='644'
dc_use_split_config='true'
dc_hide_mailname='false'
dc_mailname_in_oh='true'

Auch hier muss durch ein anschließendes Ausführen des Skriptes update-exim4.conf die Konfiguration übernommen werden.

Lokale Mailadressen umschreiben

Der Mail-Server des Internet Service Providers (ISP, Anbieter des Internetzugangs) hat normalerweise keine Kenntnis über die Wahl der Namen von Rechner- und Benutzernamen auf ihren Privatkundensystemen. Wenn jetzt eine Mail von einem picard@enterprise.starfleet.org verschickt werden soll, weil man sich selbst als picard am System enterprise in der Domäne starfleet.org anmeldet, kann es schon mal sein, dass der Mail-Server die Weiterleitung ablehnt, weil er sich für diese Domäne nicht zuständig sieht. Deshalb müssen lokale Mail-Adressen vor dem Versand über den Smarthost des Providers umgeschrieben werden. Das geschieht bei Exim über die Datei /etc/email-adresses:

# This is /etc/email-addresses. It is part of the exim package
#
# This file contains email addresses to use for outgoing mail. Any local
# part not in here will be qualified by the system domain as normal.
#
picard: jean-luc.picard@provider.example.org
riker: will.riker@provider.example.org

Wenn jetzt als Benutzer picard eine Mail geschickt werden soll, wird Exim die lokale Mail-Adresse umsetzen in jean-luc.picard@provider.example.org und erst dann an den Smarthost weiterleiten. Das gleiche gilt natürlich auch für "Nummer 1" ;-).

« nach oben

Serverseitige Filterung von Mail mit Sieve

Sieve (Sieb) ist eine einfach gehaltene Filtersprache für IMAP-Server. Cyrus bringt die Unterstützung dafür von Haus aus mit, genau genommen stammt die Einreichung des Standards von den Machern von Cyrus. Sieve ist nicht so mächtig wie z. B. procmail, so erlaubt es nicht einmal die Definition von Variablen. Hintergrund ist, dass man den Benutzern des IMAP-Servers zwar Möglichkeiten zur automatischen Behandlung ihrer Mails geben möchte, dabei aber keine Abstriche in der Sicherheit des Servers machen muss.

Die Desktopumgebung KDE bringt von Haus aus Unterstützung für Sieve mit, d. h. dass es theoretisch für KMail genutzt werden kann. Praktisch ist die Unterstützung in KMail 1.7.2 (KDE 3.3.2) aber nicht gegeben, egal wie oft man das Häckchen dafür setzt. :lol:

Inzischen bietet KMail Unterstützung für Sieve an, beschränkt sich aber dabei auf das Anlegen neuer Skripte bzw. das Aktivieren bereits existierender Skripte. Es werden keine Sieve-Regeln auf Basis des Assistenten erstellt, sondern muss wie hier beschrieben wie eine Textdatei angelegt werden.

Testen der Sieve Installation

Für die Filterung mit Sieve benötigt man drei Dinge:

  • ein Filterscript (als Ausgangspunkt gibt es hier eine Vorlage)
  • das Programm sieveshell (bei debian im Paket cyrus-admin)
  • den ansprechbaren Sieve-Dienst auf dem IMAP-Server

Testen wir erst mal, ob der Sieve-Dienst läuft:

$ telnet 192.168.1.1 sieve
Trying 192.168.1.1...
Connected to 192.168.1.1.
Escape character is '^]'.
"IMPLEMENTATION" "Cyrus timsieved v2.1.18-IPv6-Debian-2.1.18-1"
"SASL" "PLAIN"
"SIEVE" "fileinto reject envelope vacation imapflags notify subaddress relational regex"
OK
logout
OK "Logout Complete"
Connection closed by foreign host.

Wenn diese oder eine ähnliche Ausgabe stattgefunden hat, läuft der Sieve-Daemon und ist ansprechbar. Im Falle, das die Verbindung abgelehnt wird, zuerst einmal überzeugen, ob der Daemon läuft (Hinweis: Das Programm heiß bei Cyrus IMAP cyrmaster und lauscht auf Port 2000). Eventuell muss der Dienst auch in den hosts_access(5)-Dateien (/etc/hosts.deny bzw. /etc/hosts.allow) freigegeben werden. Siehe dazu auch hosts_access - Netzwerkzugriff beschränken mit dem tcpwrapper.

Sortieren der eingehenden Mails mit Sieve

Hinweis: Als Trennzeichen für Unterordner wird hier der Punkt (.) benutzt. Das ist eine spezielle Einstellung von Cyrus (unixhierarchysep: no). Ist sie auf "yes" gesetzt, gilt als Trennzeichen der Querstrich (/) und in Ordnernamen dürfen dann auch Punkte vorkommen, die aber intern als ^ umgesetzt werden.

Die meistgenutze Aufgabe von einem Sieve-Skript wird wahrscheinlich das Einsortieren spezieller Nachrichten (z.B. nach Absender) in die zugehörigen Ordner sein. Eine solche Regel sieht folgendermaßen aus:

# Datei meine_filter.script
# Kommentare beginnen wie so oft mit #
if header :contains "From" "hans@example.org"
{
  fileinto "Hans";
  stop;
}

Seltsamerweise ist das Skript so nicht vollständig und erzeugt die mehrdeutige Fehlermeldung "fileinto not required". Für mich würde das sinngemäß heißen, dass die fileinto-Zeile überflüssig ist. Aber das ist doch nicht logisch, stellt sie doch die gewünschte Aktion dar.

Hintergrund der Fehlermeldung ist, dass die Funktion fileinto erst eingebunden werden muss, bevor man sie benutzen kann. Wir fügen also vor der if-Bedingung noch die folgende Zeile ein:

# Zusatzfunktionen einbinden
require ["fileinto"];

Mit dieser require-Zeile gibt die Fehlermeldung dann wieder einen Sinn. Dennoch halte ich diese Formulierung des Fehlers für ungeschickt, da mehrdeutig. :confused:

Die eckigen Klammern kennzeichnen Listen. In diesem Fall könnten sie auch weggelassen werden, da die Liste lediglich aus fileinto besteht. Die fertige Regel würde jetzt in den eingehenden Nachrichten nach dem Absender hans@example.org suchen und bei Zutreffen die Mail in dem Ordner Hans ablegen.

Hinweis: Das anschließende stop bewirkt, dass die Abarbeitung der Regeln an dieser Stelle beendet ist.

Logisches Verknüpfen von Bedingungen mit anyof() und allof()

Jetzt kann es aber auch sein, dass Leute mehrere Mailadressen benutzen, die man aber dennoch in den gleichen Ordner schieben will. Hierzu gibt es ein weiteres Kontrollkonstrukt: anyof. Hier ein Beispiel:

# Datei meine_filter.script
[...]
# alle Mails von Gregor in seinem Ordner ablegen
if anyof (
  header :contains ["From"] "gregor@example.org",
  header :contains ["From"] "gregor@example.com"
) {
  fileinto "Freunde.Gregor";
  stop;
}

Das Konstrukt anyof() entspricht also der logischen Operation ODER. Wo ein ODER ist, kann ein AND nicht weit sein ;-) und somit gibt es dann auch ein allof()-Konstrukt, das dem logischen AND entspricht.

Ferner wurde in beiden Beispielen :contains für den Vergleich herangezogen, d. h. es wird nach einem Teilstring gesucht. Will man eine wortgenaue Übereinstimmung, muss man :is verwenden. Außerdem ist noch die Angabe eines Musters mit :matches erlaubt, das die Verwendung der Wildcards * und ? unterstützt. Hierbei steht * für beliebig viele Zeichen (also auch keins) und ? für genau ein Zeichen.

Behandlung von Mailinglisten

Im Gegensatz von Mails, die direkt an einen selbst adressiert werden, ist für Mailinglisten nicht der Absender sondern die Empfängerliste interessant. Außerdem gibt es meistens Listenfunktionen, die mit speziellen Adressen angesprochen werden. Oft werden z. B. für das ein- und austragen einfach die Suffixe -subscribe bzw. -unsubscribe angefügt. Diese Mails sollen auch erkannt und eingeordnet werden, was durch die zweite Zeile mit matches und Jokerzeichen geschieht.

if anyof (
  header :contains ["To","Cc"]
    "debian-security-announce@lists.debian.org",

  header :matches ["To","Cc"]
    "debian-security-announce-*@lists.debian.org"
) {
  fileinto "Mailinglisten.debian-security-announce";
  stop;
}

Somit werden alle Mails an die Liste debian-security-announce in den gleichnamigen Ordner einsortiert. Es emfpiehlt sich die Filter für die Mailinglisten vor den Filtern der Bekannten und Freunde zu definieren, sofern diese auch an die entsprechenden Listen posten damit diese Mails dann nicht im falschen Ordner landen.

Behandlung kompletter Domänen (z. B. Mails von einer Firma)

Als Domäne wird der Teil inter dem @ bezeichnet. Bei der Mailadresse kai@example.com ist also die Zeichenkette "example.com" die Domäne. Nützlich ist diese Art der Filterung bei Mails, die aus der Firma kommen, bei der man arbeitet oder bei Online-Shops. Letzteres soll hier als Beispiel dienen:

if allof (
  address :domain :is ["From"] "amazon.de"
  header :contains ["To"] "meine-adresse@example.org"
) {
  fileinto "Shops.Amazon"
  stop;
}

Die erste Regel trifft auf alle Mails von Amazon zu. Zusätzlich muss die Mail aber auch direkt an die bei Amazon registrierte Mailadresse geschickt worden sein (Regel 2 und "allof"). Wenn beide Regeln zutreffen, soll die Nachricht im Unterordner Amazon des Ordners Shops abgelegt werden.

Sortieren nach Größe

Eine weitere Möglichkeit der Filterung ist es, eine Aktion je nach Größe der Nachricht durchzuführen. Denkbar wäre zum Beispiel, Nachrichten mit mehr als 1 MB abzulehnen, aber dem Versender eine Nachricht darüber zu schicken, damit er oder sie weiß, dass die Nachricht nicht durchkam und warum. Hier das Beispiel aus der RFC:

require ["fileinto", "reject"];

if size :over 1M
{
  reject text:
Bitte schicken Sie mir keine Mails mit mehr als 1 MB.
Laden Sie die Datei auf einen Server und schicken Sie mir die URL.
Danke & Gruß.
  Kai
.
;
  stop;
}

Hochladen und Aktivierung des Sieve-Skripts

Nach dem obigen Muster ist nun also ein schönes Filterskript entstanden. Jetzt muss dieses Skript mit sieveshell auf den IMAP-Server übertragen und aktiviert werden.

$ sieveshell 192.168.1.1
password: ****** (IMAP-Passwort)
> put meine_filter.script
> list
meine_filter
> activate meine_filter
> list
meine_filter <- active script
> quit

Falls das Skript noch Fehler enthält, werden diese nach dem put-Kommando angezeigt. Diese Fehler müssen natürlich beseitigt werden und anschließend erneut versuchen, das Skript mit put hochzuladen. Man kann beliebig viele Skripte zur Filterung hochladen, allerdings kann man immer nur eines aktivieren. Somit müssen alle Regeln in einer Datei stehen denn ein Splitting in einzelne Dateien (z. B. mit einer Art include-Befehl) ist nicht möglich.

Die vollständigen Informationen über Sieve gibt es im RFC 3028 (englisch). Unter Anderem kann mit Sieve auch nach Mailgröße gefiltert werden und es gibt die Möglichkeit, Mails entweder direkt zu löschen oder aber auch dem Absender eine Annahmeverweigerung zu schicken.

« nach oben

« zurück (Gesammelte Anleitungen)