Andreas Bruns

Softwareentwicklung für Oldenburg und Bremen

Mails verschicken per PHP mit einem Webhosting-Dienst

Die Erstellung einer hoch interaktiven Webanwendung ist dank der vielen Javascript-Frameworks (z.B. JQuery, AngularJS, Knockout) heutzutage viel einfacher als noch vor ein paar Jahren. Damit kann viel Programmlogik jetzt auf dem Client (also im Browser) ausgeführt werden und es wird weniger Server-Programmcode benötigt. Besonders schlank wird der Server, wenn man lediglich die vom Browser gesammelten Daten per E-Mail verschicken möchte.

Viele Webhosting-Dienste bieten als serverseitige Programmiersprache PHP an. Mit der PHP-Methode mail($to,$subject,$message) können Mails verschickt werden, wenn auf dem Webserver ein lokaler Mail-Server (z.B. Sendmail oder Postfix), konfiguriert ist:

<?php
$to = 'empfaenger@domain.test';
$subject  = 'Unser Betreff';
$message  = 'Der Text der Nachricht.';
$header   = 'From: empfaenger@domain.test' . "\r\n" .
    'Reply-To: sender@domain.test' . "\r\n" .
    'X-Mailer: PHP/' . phpversion();
mail($to, $subject, $message, $header);
?>

So ein kleines Beispiel funktioniert ohne Probleme, aber was gibt es bei einer größeren Mail zu beachten? In dem folgenden Beispiel habe ich einige Best-Practices eingebunden, die ich im Internet gefunden habe:

  • Mail-Inhalt aus einer Template-Datei laden, damit der Text nicht im PHP-Skript steht
  • Auslesen von JSON-Daten (z.B. Vorname), die per POST gesendet wurden
  • Platzhalter in der Template-Datei ersetzen (z.B. Vorname)
  • eine Zeile auf unter 80 Zeichen begrenzen
  • Variablen für alle relevanten Daten verwenden
  • Header-Daten in einem Array speichern
  • Header-Array in eine Zeichenkette mit implode() in mehrere Zeilen aufteilen
  • Charset der Mail im Header definieren: UTF-8, ISO-8859-1
  • das Ergebnis der mail()-Methode auswerten
  • meine Regel aus der Java-Welt: als Zeichen-Encoding stets UTF-8 statt ISO-8859-1 nutzen

Das folgende Code-Beispiel sieht für mich schon sehr verständlich aus und eine verschickte E-Mail wurde in meinem Mail-Programm Thunderbird auch korrekt dargestellt. Innerhalb des Mail-Programms Outlook erschien allerdings ein kryptischer Zeichenblock und Sonderzeichen wurde falsch angezeigt. Das konnte ich auch im GMX-Webmailer nachvollziehen:

Hallo %vorname%,

danke für die Anfrage.

Schöne Grüße
Andreas Bruns
<?php
$message = file_get_contents('mail-template-example.txt');

$jsonString = file_get_contents('php://input');
$jsonData = json_decode($jsonString, true);
$vorname = $jsonData["Vorname"];

$message = str_replace('%vorname%', $vorname, $message);
$message = wordwrap($message, 70);

$receiver    = "empfaenger@domain.test";
$sender      = "sender@domain.test";
$bccReceiver = "blindkopie@domain.test";
$subject     = "Grüße von einer Mail";

$headers   = array();
$headers[] = "MIME-Version: 1.0";
$headers[] = "Content-Type: text/plain; charset=UTF-8";
$headers[] = "Content-Transfer-Encoding: quoted-printable";
$headers[] = "From: {$sender}";
$headers[] = "Bcc: {$bccReceiver}";
$headers[] = "Reply-To: {$sender}";
$headers[] = "Subject: {$subject}";
$headers[] = "X-Mailer: PHP/".phpversion();

$mailResult = mail($receiver, $subject, $message, implode("\r\n",$headers));
if($mailResult) {
  echo 'SUCCESS';
} else {
  echo 'ERROR';
}
?>
curl -i -X POST http://my-server.de/mail-template-example.php --data '{"Vorname": "Rüdiger"}' -H "Content-Type: application/json"
HTTP/1.1 200 OK
Date: Fri, 02 Oct 2015 13:47:21 GMT
Server: Apache
X-Powered-By: PHP/5.3.29
Content-Length: 7
Content-Type: text/html

SUCCESS
Mail: ungültige Header-Informationen

Mail: ungültige Header-Informationen

Die Ursache für den kryptischen Zeichenblock wird hier erklärt. Kurz gesagt:

  1. manche MTAs ersetzen im Header „\n“ durch „\r\n“, sodass „\r\r\n“ entsteht
  2. der Header wird nicht korrekt erkannt
  3. Mail-Dienste scannen die Mail bezüglich Spam bzw. Virus
  4. mein Mail-Dienst GMX gehört zu United Internet, daher X-UI-Filterresults
  5. Lösung: „\r\n“ durch „\n“ ersetzen

Mit einem korrekten Header sieht schon alles besser aus, aber manche Umlaute werden nicht korrekt dargestellt:

Mail: fehlerhaftes Encoding

Mail: fehlerhaftes Encoding

Falsch angezeigte Umlaute führen uns zu dem leidigen Thema: Soll ich als Zeichen-Encoding lieber UTF-8 oder ISO-8859-1 verwenden? Antworten gibt es dazu viele im Internet. Um alles kurz zu halten, liste ich einfach die für mich relevanten Punkte auf:

  • ASCII ist Teilmenge von ISO-8859-1, ISO-8859-1 ist Teilmenge von UTF-8
  • Standards und Protokolle sind historisch gewachsen, falls ein Protokoll in der Protokoll-Kette etwas nicht unterstützt dann funktioniert es nicht
  • UTF-8 sollte jetzt überall unterstützt werden -> ich nutze komplett UTF-8
  • Dateien auf UTF-8 einstellen
    • Eclipse: Datei auswählen -> File -> Properties -> Resource -> Text file encoding
    • IntelliJ IDEA: Datei auswählen -> File -> File Encoding
  • wie man am Beispiel sieht, wird der Betreff nicht korrekt angezeigt
  • aus den folgenden Optionen die passende Kombination wählen
    • Datei umstellen von UTF-8 auf ISO-8859-1
    • Content-Type im Header umstellen auf: "Content-Type: text/plain; charset=ISO-8859-1"
    • Daten konvertieren zwischen UTF-8 und ISO-8859-1
  • erster Versuch: PHP-Skript und Mail-Versand auf ISO-8859-1 umstellen, allerdings werden die UTF-8 Formulardaten des Browser dann falsch angezeigt
  • weiterer Versuch: Dateien in UTF-8, Mail-Versand in ISO-8859-1, Daten-Konvertierung mit PHP-Methode utf8_decode()
  • so klappt es – juhu 😉
Mail: korrektes Encoding

Mail: korrektes Encoding

<?php
$message = file_get_contents('mail-template-example.txt');

$jsonString = file_get_contents('php://input');
$jsonData = json_decode($jsonString, true);
$vorname = $jsonData["Vorname"];

$message = str_replace('%vorname%', $vorname, $message);
$message = utf8_decode(wordwrap($message, 70));

$receiver    = "a.bruns@gmx.de";
$sender      = "sender@domain.test";
$bccReceiver = "a.bruns@gmx.de";
$subject     = utf8_decode("Grüße von einer Mail");

$headers   = array();
$headers[] = "MIME-Version: 1.0";
$headers[] = "Content-Type: text/plain; charset=ISO-8859-1";
$headers[] = "Content-Transfer-Encoding: quoted-printable";
$headers[] = "From: {$sender}";
$headers[] = "Bcc: {$bccReceiver}";
$headers[] = "Reply-To: {$sender}";
$headers[] = "Subject: {$subject}";
$headers[] = "X-Mailer: PHP/".phpversion();

$mailResult = mail($receiver, $subject, $message, implode("\n",$headers));
if($mailResult) {
    echo 'SUCCESS';
} else {
    echo 'ERROR';
}
?>

Wenn man also Mails mit PHP verschicken möchte, dann funktioniert es oft nicht auf Anhieb. Daher beachte ich jetzt immer folgende Punkte:

  • oben genannte Best-Practices und Hinweise anwenden
  • Mail mit unterschiedlichen Mail-Clients anzeigen lassen: Outlook, Thunderbird, GMX-Webmailer
  • Verarbeitung von Sonderzeichen überprüfen: Betreff, Inhalt, ausgewertete Formular-Daten

Mit der mail()-Methode lassen sich übrigens auch HTML-Mails verschicken. Und falls man mehr benötigt (z.B. Versand von Mails über SMTP), dann lohnt sich immer ein Blick auf die Platzhirsch-Library im PHP-Umfeld: PHPMailer

Kommentare sind geschlossen.