Mailversand mit PHP aus einem Docker-Container

Wie in den letzten Artikeln beschrieben, läuft WordPress im Docker-Container bzw. im Docker Swarm Mode. Auf den meisten Web-Sites gibt es eine Möglichkeit, Kontakt aufzunehmen, beispielsweise per Kontaktformular.

Im einfachsten Fall werden die eingegebenen Daten gesammelt und dem Betreiber der Web-Site per Mail zugestellt. Unter WordPress kann ein derartiges Kontaktformular z.B. mit dem Plugin “Contact Form 7” realisiert werden. Ein erster Test war jedoch zunächst nicht erfolgreich, das Formular konnte nicht abgeschickt werden, und die Fehlermeldung war nicht sonderlich aussagekräftig.

Mailversand mit PHP

Nun gibt es in PHP mehrere Möglichkeiten, eine Mail zu versenden. PHP bietet z.B. die Funktion mail(), die letztlich nichts anderes macht, als die übergebenen Parameter wie Empfänger, Nachricht und weitere Header-Angaben (worin sich etwa eine benutzerdefinierte Absenderadresse verbergen kann) einem lokal verfügbaren Programm zu übergeben. Das kann etwa Sendmail sein, oder auch Postfix, wobei es unter Linux bzw. Unix darauf ankommt, dass das Programm, was die Angaben entgegen nimmt, unter einem bestimmten Pfad verfügbar ist. Dieser Pfad kann wiederum per php.ini definiert werden. Unter Windows sieht es wiederum anders aus, dort wird ein MTA (Mail Transport Agent) benötigt, d.h. ein klassischer Mailserver, der auf einem bestimmten Socket lauscht. Kurzum – die Situation ist etwas suboptimal, daher existieren auch Libraries wie SwiftMailer oder zend-mail, die sowohl die Mail-Generierung als auch den Mailversand etwas komfortabler werden lassen und insbesondere für den Mailversand verschiedene Optionen bieten.

Mailversand mit WordPress

WordPress selbst setzt auf PHPMailer, wobei die Konfiguration etwas suboptimal ist. Im speziellen Fall existieren wiederum Plugins wie “WP Mail SMTP“, mit denen der Transportweg der Mail modifiziert werden kann.

Mailversand mit PHP aus einem Docker-Container 1

So kann statt der Standard-Methode mit den PHP-eigenen Funktionen ein SMTP-Server angesprochen werden, wobei zusätzlich Default-Konfigurationen für Gmail, Mailgun und Sendgrid existieren, letztere dürften hierzulande weniger gebräuchlich sein. Praktisch ist ebenfalls die Möglichkeit, den Versand einer Mail aus WordPress zu testen, ohne jedes Mal ein Kontaktformular oder ähnliches abschicken zu müssen. Insofern hätte das Plugin eine Lösung sein können, sie wäre jedoch auf WordPress beschränkt gewesen. Bei Nutzung anderer Anwendungen, Frameworks oder allgemein PHP-Skripten hätten insofern andere Lösungen verwendet werden müssen. Ein allgemeinerer Ansatz musste hier.

Mailversand aus dem Docker-Container

Die erste Idee bestand darin, tatsächlich einen SMTP-Server bzw. MTA innerhalb des PHP-Docker-Containers einzurichten. Nur widerspricht genau dies dem Gedanken, dass in einem Container nur ein Server-Dienst gestartet werden sollte. Einen zusätzlicher Postfix- oder Sendmail-Dienst auf demselben Host zu starten, entsprach jedoch ebenfalls nicht meinen Vorstellungen – es wäre verbunden gewesen mit zusätzlichem Konfigurationsaufwand, etwa um den Mail-Server erstmal nur lokal lauffähig und sicher zu betreiben, andererseits wäre der Overhead vergleichsweise hoch gewesen, denn letztlich hätte für jeden Docker-Stack dem Schema folgend wiederum ein eigener Mail-Server eingerichtet werden müssen. Letztlich würde es jedoch ausreichen, der PHP-Installation ein Programm anzubieten, was den Mailversand übernimmt. Ein vollständiger Mailserver ist dazu gar nicht notwendig. Eine Lösung für den Mailversand bietet das Programm sSMTP. Es nimmt Mails lokal entgegen und versendet diese an einen (entfernten) Mailserver. Die Konfiguration ist dabei relativ simpel und wird durch eine Datei /etc/ssmtp/ssmtp.conf erledigt. Der Vorteil gegenüber eines vollständigen Mail-Servers bzw. MTAs besteht darin, dass innerhalb des Docker-Containers kein zusätzlicher Dienst gestartet werden muss. Des Weiteren ist keine Änderung gegenüber der Standard-Konfiguration von PHP notwendig, da sSMTP sich auf dem Standard-Pfad von sendmail einrichtet. Die aktuelle Version des php-fpm-swrm-Images beinhaltet bereits sSMTP, in einem entsprechenden Container stellt es sich wie folgt dar:

root@c1fdf711449c:/usr/share/nginx# ls -l /usr/sbin/sendmail
lrwxrwxrwx 1 root root 5 Apr  3 12:44 /usr/sbin/sendmail -> ssmtp

Somit ist “sendmail” ein symbolischer Link auf die Binärdatei von sSMTP. Zwar existiert eine Default-Konfigurationsdatei /etc/ssmtp/ssmtp.conf, doch falls nicht eine bestimmte Konfiguration zufällig vorliegt, muss die Datei angepasst werden. Denn in der Konfiguration ist als “mailhub” der Name “mail” genannt. Somit versucht sSMTP beim Mailversand, den Rechnernamen “mail” aufzulösen, was in den meisten Fällen fehlschlagen dürfte. Die Konfiguration beschränkt sich jedoch auf wenige Änderungen, je nach dem, an welchen Mailserver die Mails zugestellt werden sollen. Da ich einen Mailserver betreibe, der die Mails für meine Domains entgegen nimmt, bestand die Anpassung aus der Zeile bzgl. “mailhub“. Die vollständige Datei ssmtp.conf sieht somit wie folgt aus:

#
# Config file for sSMTP sendmail
#
# The person who gets all mail for userids < 1000
# Make this empty to disable rewriting.
root=postmaster

# The place where the mail goes. The actual machine name is required no
# MX records are consulted. Commonly mailhosts are named mail.domain.com
mailhub=mail.geschke.name

# Where will the mail seem to come from?
#rewriteDomain=

# The full hostname
hostname=rostock.mushaake.org

# Are users allowed to set their own From: address?
# YES - Allow the user to specify their own From: address
# NO - Use the system generated From: address
#FromLineOverride=YES

Ein Beispiel zur Verwendung der Gmail-Server findet sich auf der Debian-Wiki-Seite.

Nun muss nur noch die neue Konfiguration eingebunden werden – wie bei Docker üblich wird die Datei einfach in den Container gemountet. Da hier der PHP-Container zum Einsatz kommt, habe ich die Verzeichnisstruktur einfach wie folgt erweitert:

services/geschkename/
                    /mariadb/...
                    /nginx/...
                    /php/
                        /conf.d/
                                99-custom.ini
                        /ssmtp/
                               ssmtp.conf

Im docker-compose-File wird somit die entsprechende, hier letzte Zeile hinzugefügt:

version: '3.3'
services:
  nginx_geschkename:
  [...]
  phpbackend_geschkename:
    image: geschke/php-fpm-swrm
    volumes:
      - type: bind
        source: ./html
        target: /var/www/html
      - ./php/conf.d/99-custom.ini:/etc/php/7.2/fpm/conf.d/99-custom.ini:ro
      - ./php/ssmtp/ssmtp.conf:/etc/ssmtp/ssmtp.conf:ro
[...]

Danach kann einfach der Stack neu gestartet werden, wobei zu beachten ist, dass das aktuelle php-fpm-swrm-Image vorliegen muss:

geschke@waren:~/services/geschkename$ docker stack rm geschkename
Removing service geschkename_mariadb_geschkename
Removing service geschkename_nginx_geschkename
Removing service geschkename_phpbackend_geschkename
Removing config geschkename_nginx_config_default

geschke@waren:~/services/geschkename$ docker stack deploy -c website_www_geschke_name.yml geschkename
Creating config geschkename_nginx_config_default
Creating service geschkename_nginx_geschkename
Creating service geschkename_phpbackend_geschkename
Creating service geschkename_mariadb_geschkename

Fazit

Für den Mailversand aus einem Docker-Container heraus eignet sich ein ressourcenschonender und einfacher Ansatz wie sSMTP sehr gut. Die Konfiguration ist vergleichsweise einfach und somit schnell erledigt. Dabei sollte berücksichtigt werden, dass sSMTP keinen vollwertigen Mailserver ersetzen kann, dies aber auch gar nicht will. Für den Versand von Massen-Mails oder Newslettern ist diese Lösung daher nicht geeignet, wobei sich dann wiederum die Frage stellt, ob Derartiges mit WordPress und/oder PHP überhaupt sinnvoll wäre.

2 Gedanken zu „Mailversand mit PHP aus einem Docker-Container“

  1. Guten Tag Ralf Geschke,

    der Besucher einer/meiner Webseite soll über ein Kontaktformular eine Art offenen Brief in Form einer E-Mail an verschiedene Personen, unter Angabe es tatsächlichen Absenders senden.
    Mit CF7 scheint das nicht zu klappen.
    Kurzer Hintergrund: es wurde eine sanierungsbedürftige Brücke über eine Bahnlinie ersatzlos abgerissen und es soll erreicht werden dass eine neue für Fussgänger und Radfahrer errichtet wird.
    Ich bin kein Programmierer, könnte mir aber vorstellen dass dieser Beitrag etwas mit meiner Idee zu tun hat.

    Über einen Antwort, einen Hinweis würde ich mich sehr freuen. Habe auch im WP-forum diese Frage gestellt.

    Viele Grüße
    Martin Kokemoor

    1. Hallo Martin!

      Sorry fürs späte Freischalten, irgendwie ist mir Dein Kommentar völlig untergegangen. Irgendwie geht alles, aber die erste Frage, die sich mir stellt, lautet: Wer sind die “verschiedenen Personen”? Soll der Besucher der Website die Adressaten auswählen können? Und mit der Angabe des “tatsächlichen Absenders” meinst Du vermutlich, dass die Besucher ihren Namen und/oder Mailadresse eingeben können, so dass diese Angaben dann in der versendeten E-Mail erscheinen? Davon würde ich vehement abraten, da mit hoher Wahrscheinlichkeit diese Funktion binnen kürzester Zeit von Spammern missbraucht werden würde. Also ohne Verifizierung bzw. Bestätigung der eingegebenen Mailadresse sollte eine solche Funktion nicht ins Netz gestellt werden. Und dann wird’s auch schon wieder ein wenig komplexer, aber evtl. gibt es dafür auch passende Plugins. Leider ist mir ad hoc keines bekannt, daher kann ich hier nicht wirklich helfen. Vielleicht wäre für Deinen Fall die Nutzung einer der Petitions-Plattformen (change.org, openpetition etc.) möglich und sogar sinnvoller als hier etwas Eigenes zu bauen.

      Beste Grüße,
      Ralf

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Tags: