Sendmail mit User-Transport

In Postfix gibt es den benutzerbasierten Transport für die Umleitung von z.B. einzelnen E-Mail-Adressen oder ganzen Domains an einen anderen SMTP-Server. Die Mailertable in Sendmail arbeitet jedoch nur auf Domain-Ebene. Wie lässt sich ein benutzerbasierter Transport mit Sendmail realisieren?

Über die Transport-Tabelle können im Postfix-Mailserver einzelne E-Mail-Adressen oder ganze Domains an einen anderen SMTP-Server umgeleitet werden. Dabei wird die E-Mail-Adresse des Empfängers nicht umgeschrieben, sondern die E-Mail wird lediglich an einen abweichenden SMTP-Server umgeleitet, ohne dass (wie normalerweise üblich) der MX-Eintrag berücksichtigt wird. Die Transport-Tabelle wird oftmals auch als "Transport Map" bezeichnet und das zuvor beschriebene Verhalten wird von Postfix-Administratoren gerne als "user-based transport" bezeichnet. Der schon deutlich länger existierende Sendmail-Mailserver realisiert diese Funktionalität über die Mailertable, allerdings agiert diese nur auf Domain-Ebene, so dass Umleitungen für einzelne E-Mail-Adressen damit leider nicht möglich sind.

In diesem realitätsnahen Beispiel gehen wir davon aus, dass der MX-Eintrag der Domain example.net auf tux.example.net zeigt - einen Linux-Server mit Sendmail, welcher sowohl mit dem Internet, als auch mit dem privaten Netzwerk verbunden ist. E-Mails an robert@example.net sollen an den internen Mailserver beastie.example.net zugestellt werden, der interne Mailserver puffy.example.net soll E-Mails für patrick@example.net erhalten und an die IPv4-Adresse 192.0.2.4 sollen E-Mails für root@example.net übermittelt werden. Zudem sollen E-Mails an hostmaster@example.net einfach nur auf root@example.net umgeleitet, aber E-Mails an postmaster@example.net sollen zum einen auf robert@example.net umgeleitet und zum anderen an den internen Mailserver puffy.example.net zugestellt werden. E-Mails an alle anderen E-Mail-Adressen sollen mit einer Fehlermeldung abgewiesen werden.

Als erstes muss die Sendmail-Konfiguration in üblicherweise /etc/mail/sendmail.mc um folgende Zeilen erweitert werden:

LDAPROUTE_DOMAIN(`example.net')dnl
FEATURE(`ldap_routing', `hash -o /etc/mail/transport.db', `hash -o /etc/mail/virtusertable.db', `bounce')dnl

Das interessante und zugleich wichtige an diesem Sendmail-Feature "ldap_routing" ist, dass nicht zwingend LDAP verwendet werden muss. Zwar soll damit die LDAP-basierte Umleitung von einzelnen E-Mail-Adressen an einen anderen Server im Intranet gemäß dem IETF Internet Draft LDAP Schema for Intranet Mail Routing in Sendmail abgebildet werden, doch letztendlich wird das Ergebnis aus der LDAP-Abfrage nur als sogenannte "Map" erwartet. Und an dieser Stelle wird die Map lediglich - anstatt über LDAP - aus einem Hash befüllt. Je nach dem, wie Sendmail kompiliert wurde, könnte statt der Hash-Map auch eine DBM-Map zum Einsatz kommen.

Die zuvor im zweiten Argument referenzierte Hash-Map /etc/mail/transport enthält nachfolgendes:

robert@example.net esmtp:[beastie.example.net]
patrick@example.net esmtp:[puffy.example.net]
root@example.net esmtp:[192.0.2.4]
postmaster@example.net esmtp:[puffy.example.net]

Statt esmtp könnte hier beispielsweise smtp als Sendmail-Mailer genutzt werden, wenn der Ziel-Mailserver kein Extended SMTP unterstützt. Der Sendmail-Mailer ist im Postfix-Jargon häufig als Transport-Methode bekannt; dort wird allerdings smtp sowohl für SMTP, als auch für Extended SMTP verwendet. In der Praxis unterstützen die meisten Mailserver jedoch Extended SMTP bereits seit vielen Jahren, so dass esmtp als Sendmail-Mailer fast immer die richtige Wahl ist. Die [eckigen Klammern] um den Hostnamen bzw. die IPv4-Adresse unterdrücken die Abfrage auf einen MX-Eintrag. Je nach Situation kann die Berücksichtigung des MX-Records in bestimmten Fällen gewünscht sein, aber es muss sichergestellt werden, dass keine Mailloop entsteht. Bei IPv6 würde der Eintrag übrigens z.B. so aussehen:

root@example.net esmtp:[IPv6:2001:db8::4]

Die Hash-Map /etc/mail/virtusertable aus dem dritten Argument würde wie folgt befüllt werden:

hostmaster@example.net root@example.net
postmaster@example.net robert@example.net

Das vierte Argument bounce ist optional und sorgt für die Abweisung der E-Mail (und müsste meines Erachtens daher eigentlich reject heißen, da kein klassischer Bounce, sondern wirklich ein Reject entsteht). Wird kein viertes Argument übergeben, gilt der Standardwert passthru, welcher für die Zustellung der E-Mail an die originale E-Mail-Adresse sorgt, wenn kein Treffer in einer der beiden vorhergehenden Maps gefunden wird.

Zum Aktivieren der Anpassungen führen Sie bitte die nachfolgenden Befehle aus. Benutzer einer älteren Version des SuSE Linux Enterprise Servers verwenden statt service sendmail restart am besten rcsendmail restart, um Sendmail neu zu starten.

tux:~ # make -C /etc/mail transport.db all
make: Entering directory `/etc/mail'
make: Leaving directory `/etc/mail'

tux:~ #
tux:~ # service sendmail restart
Shutting down sm-client: [ OK ]
Shutting down sendmail: [ OK ]
Starting sendmail: [ OK ]
Starting sm-client: [ OK ]

tux:~ #

Je nach Linux-Distribution ist der Aufruf von make abweichend, da das Makefile bzw. die Hilfsskripte unterschiedlich flexibel (oder auch unflexibler, wie beispielsweise bei Ubuntu) gestaltet worden sind. Im Zweifelsfall funktionieren die nachfolgenden beiden Aufrufe immer, wenn eine Hash-Map eingesetzt wird:

tux:~ # makemap hash /etc/mail/transport.db < /etc/mail/transport
tux:~ #
tux:~ # makemap hash /etc/mail/virtusertable.db < /etc/mail/virtusertable
tux:~ #

Zum Testen der neuen Konfiguration könnte man jetzt testweise mehrere E-Mails versenden - man kann jedoch auch nur die Namensverifikation von Sendmail verwenden. Die Testmails sind vermutlich dennoch nicht erlässlich, um mögliche Fehlerquellen wie Firewall-Konfiguration, DNS-Probleme oder Konfigurationsfehler auf einem der anderen internen Mailserver ausschließen zu können. Als erstes die Prüfung für robert@example.net:

tux:~ # sendmail -bv robert@example.net
robert@example.net... deliverable: mailer esmtp, host [beastie.example.net], user robert@example.net
tux:~ #

E-Mails an robert@example.net werden per Extended SMTP an den internen Mailserver mit dem DNS-Namen beastie.example.net an die E-Mail-Adresse robert@example.net übermittelt. Dies funktioniert damit wie gewünscht, als nächstes die Prüfung für patrick@example.net:

tux:~ # sendmail -bv patrick@example.net
patrick@example.net... deliverable: mailer esmtp, host [puffy.example.net], user patrick@example.net
tux:~ #

E-Mails an patrick@example.net werden per Extended SMTP an den internen Mailserver mit dem DNS-Namen puffy.example.net an die E-Mail-Adresse patrick@example.net übermittelt - äquivalent dem vorhergegangenen Beispiel. Und genau so verhält es sich bei der Prüfung für root@example.net:

tux:~ # sendmail -bv root@example.net
root@example.net... deliverable: mailer esmtp, host [192.0.2.4], user root@example.net
tux:~ #

E-Mails an root@example.net werden per Extended SMTP an den internen Mailserver mit der IPv4-Adresse 192.0.2.4 an die E-Mail-Adresse root@example.net übermittelt. Bei E-Mails an hostmaster@example.net war lediglich eine Umleitung gewünscht:

tux:~ # sendmail -bv hostmaster@example.net
hostmaster@example.net... deliverable: mailer esmtp, host example.net., user root@example.net
tux:~ #

Das Ergebnis ist, dass E-Mails an hostmaster@example.net erst nach einem MX-Lookup (also einer Abfrage des MX-Eintrages) für example.net per Extended SMTP zugestellt werden. Diese DNS-Abfrage liefert - entsprechend der urspünglich beschriebenen Situation - dann tux.example.net zurück, also den gleichen Server. Lediglich die Zustellung erfolgt an die abweichende E-Mail-Adresse root@example.net, welche als lokales Postfach konfiguriert sein könnte. Nachfolgend die Prüfung des letzten gewünschten benutzerbasierten Transports für postmaster@example.net:

tux:~ # sendmail -bv postmaster@example.net
postmaster@example.net... deliverable: mailer esmtp, host [puffy.example.net], user robert@example.net
tux:~ #

Hierbei dürfte es sich in der Praxis vermutlich um eine eher seltenere Variante handeln, bei der E-Mails an postmaster@example.net an den internen Mailserver mit dem DNS-Namen puffy.example.net an die E-Mail-Adresse robert@example.net übermittelt werden. Die erfolgreiche Übermittlung wiederum setzt jedoch natürlich noch voraus, dass die E-Mail-Adresse robert@example.net auf puffy.example.net auch entsprechend eingerichtet ist, da E-Mails an robert@example.net eigentlich gemäß dieser Beispielsituation an beastie.example.net übermittelt werden. Ist die E-Mail-Adresse auf puffy.example.net nicht konfiguriert, so wird eine E-Mail beispielsweise mit einem Reject oder Bounce zurückgewiesen. Zu guter Letzt noch eine Prüfung auf eine nicht existierende E-Mail-Adresse:

tux:~ # sendmail -bv unbekannt@example.net
unbekannt@example.net... User unknown
tux:~ #

E-Mails an nicht existierende E-Mail-Adressen werden nun wunschgemäß mit einer Fehlermeldung abgewiesen. Die zuvor gezeigten Möglichkeiten sind die vermutlich gebräuchlichsten, allerdings nicht vollständig. Nicht berücksichtigt wird in meinem Beispiel die möglicherweise ebenfalls noch konfigurierte Mailertable, die für lokal konfigurierte Domains abgearbeitet wird. Für weitergehende Konfigurationen empfiehlt es sich in jedem Fall, die Dokumentation zum Sendmail-Feature "ldap_routing" zu konsultieren - insbesondere die dortige Übersichtstabelle.

Der Kreis zum optionalen LDAP schließt sich aber irgendwo wieder, wenn man nun bedenkt, dass für die interne E-Mail-Kommunikation zwischen beastie.example.net, puffy.example.net und 192.0.2.4 jeweils eine entsprechende Mailserver-Konfiguration benötigt wird, da sich jeder dieser Mailserver standardmäßig vermutlich für die Domain example.net zuständig fühlt. Das bedeutet, dass E-Mails von beastie.example.net an z.B. patrick@example.net lokal zugestellt werden, was ohne benutzerbasierten Transport, Alias oder eine andere Konfiguration natürlich fehlschlägt.

Sendmail 8.14.4 versucht beim zweiten und dritten Argument automatisch immer ein -T<TMPF> einzufügen, was inbesondere bei LDAP-freien Konfigurationen wie dieser zu nachfolgender Warnung führt. Eigentlich handelt es sich dabei um eine Fehlermeldung, da keine verwendbare Sendmail-Konfigurationsdatei /etc/mail/sendmail.cf erzeugt wird.

tux:~ # make -C /etc/mail transport.db all
make: Entering directory `/etc/mail'
*** WARNING: missing -T<TMPF> in first argument of FEATURE(`ldap_routing')
*** WARNING: missing -T<TMPF> in second argument of FEATURE(`ldap_routing')
make: Leaving directory `/etc/mail'

tux:~ #

Das Problem ist bereits seit Sendmail 8.14.5 behoben (oder siehe Errata-Abschnitt bei 8.14.4), allerdings liefern einige Linux-Distributionen weiterhin eine nicht korrigierte Version aus. Für Red Hat Enterprise Linux 6 gibt es den Bugreport #890227, umgangen werden kann das Problem alternativ durch das entsprechende manuelle Einfügen von -T<TMPF> in beide Argumente, also z.B. hash -T<TMPF> -o /etc/mail/transport.db.

In der Praxis kommt dieser benutzerbasierte Transport ohne LDAP vor allem in heterogenen Umgebungen zum Einsatz, wo die Aufteilung der E-Mail-Adressen auf unterschiedliche Mailserver zur Lastverteilung in der abgeschotteten DMZ erfolgt oder aber eine ausfallfreie Migration von Benutzerkonten von einem Mailserver auf einen anderen benötigt wird.