PHP/Tutorials/Symfony Mailer
Als Formmailer wird ein Programm bezeichnet, das Formular-Eingaben per E-Mail versendet. Es gibt dabei zwar die Möglichkeit, die in einem HTML-Formular getätigten Eingaben durch ein mailto:
im action
-Attribut per E-Mail zu versenden. Allerdings ist diese Methode nicht sonderlich zuverlässig, da sie vom Browser und E-Mail-Programm des Benutzers abhängig ist.
Ein Kontaktformular ist ein spezieller Formmailer, der lediglich den Namen, die E-Mail-Adresse und eine Nachricht abfragt und per E-Mail an den Betreiber versendet. Dabei sollte allerdings – auch aus rechtlichen Gründen – immer auch die E-Mail-Adresse zusätzlich angegeben werden[1].
Deshalb wird an dieser Stelle ein Formmailer vorgestellt, der den größten Teil seiner Mächtigkeit durch den Einsatz einer auf diesen Einsatzzweck spezialisierten Bibliothek namens Symfony Mailer erreicht. S... Mailer ist Open Source (MIT-Lizenz), PHP muss mindestens in Version 7.2 vorhanden sein.[2]
Die hier verwendete Bibliothek erfüllt sehr viele typische Wünsche, die man beim Mailen haben kann. Vor allem muss man sich mit den Details zur korrekten Implementierung, Codierung, dem Escaping etc. nicht mehr herumärgern, dies wird alles zuverlässig von der Bibliothek erledigt. Auch das Versenden von Anhängen ist problemlos möglich.
Symfony Mailer hält sich an gute, etablierte Standards hinsichtlich der Benennung von Klassennamen (bekannt als PSR-0-kompatibel) und ist auch deshalb zu empfehlen.
Inhaltsverzeichnis
Notwendige Vorbereitungsarbeit
Symfony Mailer ist eine Bibliothek, kein gebrauchsfertiges Programm, deshalb ist es notwendig, einige wenige Schritte vorzunehmen, um eine Mail abzusenden.
- Laden Sie Symfony Mailer mittels Composer (
composer require symfony/mailer
) herunter. Composer übernimmt auch das Auflösen und Installieren der Abhängigkeiten des Symfony Mailers; dies sind weitere Pakete, die von Symfony Mailer benötigt werden. - Speichern Sie das unten stehende Skript und passen Sie es an. Insbesondere müssen Sie gültige SMTP-Zugangsdaten eines E-Mail-Accounts eintragen. Diese wird Ihnen Ihr Webhoster bzw. E-Mail-Provider wie posteo, mailbox.org, GMX oder Gmail bereitstellen. Die Provider stellen in der Regel eine Anleitung bereit, wie man einen E-Mail-Account in einem E-Mail-Programm einrichten kann, dieser können Sie die SMTP-Zugangsdaten entnehmen.
<?php
// An welche Adresse sollen die Mails gesendet werden?
$zieladresse = 'IhrName@EXAMPLE.org';
// Welche Adresse soll als Absender angegeben werden?
// (Manche Hoster lassen diese Angabe vor dem Versenden der Mail ueberschreiben)
$absenderadresse = 'ihrAndererName@EXAMPLE.org';
// Welcher Absendername soll verwendet werden?
$absendername = 'Formmailer';
// Welchen Betreff sollen die Mails erhalten?
$betreff = 'Feedback';
// Zu welcher Seite soll als "Danke-Seite" weitergeleitet werden?
// Wichtig: Sie müssen hier eine gültige HTTP-Adresse angeben!
$urlDankeSeite = 'http://www.EXAMPLE.org/IhrName/IhreSeite.htm';
// Welche(s) Zeichen soll(en) zwischen dem Feldnamen und dem angegebenen Wert stehen?
$trenner = ":\t"; // Doppelpunkt + Tabulator
// Swift Mailer über den von Composer verwalteten Autoloader laden:
require __DIR__ . '/vendor/autoload.php';
/**
* Ende Konfiguration
*/
if ($_SERVER['REQUEST_METHOD'] === "POST") {
$message = new Swift_Message($betreff); // Ein Objekt für die Mailnachricht erzeugen.
$message
->setFrom(array($absenderadresse => $absendername))
//->attach(Swift_Attachment::fromPath('/path/to/document.pdf'))
->setTo(array($zieladresse)); // alternativ existieren setCc() und setBcc()
$mailtext = "";
foreach ($_POST as $name => $wert) {
if (is_array($wert)) {
foreach ($wert as $einzelwert) {
$mailtext .= $name.$trenner.$einzelwert."\n";
}
} else {
$mailtext .= $name.$trenner.$wert."\n";
}
}
$message->setBody($mailtext, 'text/plain');
$transport = (new Swift_SmtpTransport('smtp.example.org', 587, 'tls'))
->setUsername("username@example.org")
->setPassword("passwort_hier_einfuegen");
$mailer = new Swift_Mailer($transport);
$result = $mailer->send($message);
if ($result == 0) {
die("Mail konnte nicht versandt werden.");
}
header("Location: $urlDankeSeite");
exit;
}
header("Content-type: text/html; charset=utf-8");
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<title>PHP-Formmailer mit Swift Mailer</title>
</head>
<body>
<h1>Beispielformular</h1>
<!-- ohne action-Attribut wird das Formular immer an die aktuelle Seite gesendet -->
<form method="post">
<!-- Hier die eigentlichen Formularfelder eintragen. Die folgenden sind Beispielangaben. -->
<dl>
<dt>
<label for="versender">Ihr Name</label>:
</dt>
<dd><input name="Versender" id="versender"></dd>
<dt><label for="e-mail">Ihre E-Mail</label>:</dt>
<dd><input type="email" name="E-Mail" id="e-mail"></dd>
<dt>Sie können:</dt>
<dd>
<input type="checkbox" name="kannwas[]" value="HTML" id="kann-html">
<label for="kann-html">HTML</label>
<input type="checkbox" name="kannwas[]" value="PHP" id="kann-php">
<label for="kann-php">PHP</label>
</dd>
<dt>Sie sind:</dt>
<dd>
<input type="radio" name="sexus" value="Mann" id="sind-mann">
<label for="sind-mann">Mann</label>
<input type="radio" name="sexus" value="Frau" id="sind-frau">
<label for="sind-frau">Frau</label>
<input type="radio" name="sexus" value="Divers" id="sind-divers">
<label for="sind-divers">Divers</label>
</dd>
<dt>
<label for="sie-moegen">Sie mögen</label>:</dt>
<dd>
<select name="Browser" id="sie-moegen">
<option value="Firefox">Firefox</option>
<option value="Chrome">Chrome</option>
<option value="Edge">Edge</option>
<option value="Opera">Opera</option>
</select>
</dd>
<dt><label for="bemerkungen">Bemerkungen</label>:</dt>
<dd>
<textarea name="Bemerkungen" rows="3" cols="20" id="bemerkungen">Bemerkungen</textarea>
</dd>
</dl>
<!-- Ende der Beispielangaben -->
<button>Senden</button>
</form>
</body>
</html>
Zunächst werden im Script einige Einstellungen festgelegt. Was die einzelnen Optionen bewirken, können Sie den Kommentaren an den entsprechenden Stellen entnehmen.
Als nächstes wird geprüft, ob ein POST-Request vorliegt. Diese Prüfung soll verhindern, dass eine leere Mail abgeschickt wird, wenn das Script zum ersten Mal aufgerufen wird, denn dann soll der HTML-Teil angezeigt werden.
Steht dieses Formular dagegen öffentlich für jedermann im Internet zur Verfügung, beispielsweise als Kontaktformular, so ist ein Token-basierter Schutz gegen CSRF sinnvoll, falls dies der Nebeneffekt einer Reloadsperre ist.
Anschließend bereitet das Script ein Objekt für die zu sendende Mail vor und stellt zunächst die konfigurierten Werte für Absender, Empfänger und Betreff ein. Dann legt das Script die Variable $mailtext
leer an, um darin den Mailtext zu sammeln.
Danach geht es mit foreach()
sämtliche Elemente des $_POST
-Arrays durch und schreibt den Namen des Elementes, das Trennzeichen (definiert in $trenner
) und den Inhalt des Elementes in die Variable $mailtext
. Sollte ein Element ein Array sein, was ja bei Checkboxen und Auswahllisten mit Mehrfachauswahl der Fall ist, geht das Script mit foreach()
das Unterarray durch und verfährt mit den Elementen genauso, wie mit allen anderen Variablen auch.
Am Ende wird der Mailtext dem Message-Objekt zugewiesen, ein Mailer-Objekt mit der Transportmethode „SMTP Transport“ konfiguriert, und die Mail verschickt. Die Methode send()
gibt die Anzahl erfolgreich ausgelieferter Mails als Ergebnis zurück – wenn dieser Wert 0 ist, wurde keine Mail versendet, und das Skript bricht mit die()
und einer Fehlermeldung ab. Andernfalls wird noch zur in $urlDankeSeite
definierten Danke-Seite weitergeleitet und das Script mit exit()
verlassen.
Wenn das Formular nicht abgesendet wurde, sondern das Script direkt aufgerufen wurde, wird nur das Formular angezeigt. Dieses können Sie frei bearbeiten und weitere oder andere Formularelemente einbauen. Der Name der Script-Datei ist frei wählbar, sollte aber auf ".php" enden.
Vorteile gegenüber Eigenbaulösungen
Das Internet ist voll von Tutorials, die direkt die mail()-Funktion von PHP benutzen und dabei teilweise auch komplexe Funktionalität wie den Versand von Anhängen unterstützen. Dabei wird allerdings nicht immer auf Sicherheit geachtet, wie dieses Beispiel aus dem SELFHTML-Forum zeigt.
Zudem ist die korrekte Implementierung der eine E-Mail-Nachricht betreffenden RFC-Standards nicht gerade trivial. Stattdessen ist man hier gut beraten, auf eine etablierte und gut getestete Bibliothek zurückzugreifen.
Bei Symfony Mailer ist das Setzen von Betreff, Sender, Empfänger, der eigentlichen Nachricht, etc. sehr einheitlich gelöst: Es werden immer Methoden des erzeugten Message-Objekts aufgerufen. Die Übergabe von Mailadressen der Form "Name + Adresse" ist ebenfalls sehr einfach und ohne Kenntnis der vorzunehmenden Codierung möglich, während man sich beim einfachen Formmailer darum mühsam manuell kümmern muss.
Ein weiterer Vorteil gegenüber der Verwendung der mail()
-Funktion von PHP ist die Portabilität des Skripts. mail()
ist leider nicht 100% zuverlässig benutzbar, weil sie sich je nach Systemkonfiguration unterscheiden kann. Dies kann dazu führen, dass ein Skript, welches auf dem Testsystem Mails versenden konnte, auf dem Produktivsystem dazu nicht mehr in der Lage ist und umgekehrt. In diesem Beispiel wird auf SMTP zugegriffen, sodass mit gültigen Zugangsdaten für einen SMTP-Server E-Mails von jedem System mit Internet-Zugriff aus versendet werden kann. Symfony Mailer bietet zusätzlich zur Nutzung des SMTP-Transports noch den Versand direkt über den Unix-Befehl sendmail
(damit wird direkt der installierte System-Mailserver kontaktiert), in dem Fall sind dann keine SMTP-Zugangsdaten nötig:
$transport = new Swift_SendmailTransport(ini_get('sendmail_path'));
ini_get
wird der in der Konfiguration von PHP hinterlegte Pfad zum installierten Sendmail herausgefunden und ein SendmailTransport-Objekt erstellt, das anstatt des SmtpTransport-Objekts benutzt wird – der restliche Code ändert sich nicht. Allerdings kann es sein, dass Sendmail nicht installiert ist.Details zu den Transports sind in der Swift-Mailer-Doku zu finden.
Seine Stärken voll ausspielen kann Swift Mailer, wenn es um weitergehende Anforderungen an die zu sendende Mail geht. Beispielsweise ist es sehr einfach, der Nachricht eine auf dem Server gespeicherte Datei anzuhängen.
$message->attach(Swift_Attachment::fromPath('/path/to/image.jpg'));
Diese eine Zeile Code reicht aus, die Datei im angegebenen Pfad als Attachment der Mail hinzuzufügen, ohne dass andernorts irgendwelche Veränderungen notwendig sind.
Das Versenden von Mails mit parallelem HTML- und Plaintext-Inhalt, angereichert mit ins HTML eingefügten Bildern, ist von der Struktur her mit Swift Mailer schon etwas aufwendiger – ohne Swift Mailer allerdings kommt man um ein intensives Studium der einschlägigen RFC nicht herum.
Mit Swift Mailer sind eigene Erweiterungen des gewünschten Versandformats der Mail sehr leicht zu realisieren, was ohne helfende Bibliothek zwar möglich, aber sehr viel aufwendiger ist.
Wenn Sie in Ihrem Formular Checkboxen oder Auswahllisten mit Mehrfachauswahl einbauen wollen, muss der Name dieser Felder mit einem []
enden, damit PHP weiß, dass es die Daten als Array behandeln soll. Im Beispielformular wird dies anhand der Checkboxen demonstriert.
Vor dem Aufruf der Funktion header()
darf das Script nichts ausgegeben haben (z.B. über print und echo), weil ansonsten ein Fehler erzeugt wird. Das bedeutet auch, dass vor dem PHP-Code, eingegrenzt durch <?php ... ?>
, kein HTML-Code sowie keine Leerzeichen und Leerzeilen stehen dürfen. <?php
muss also direkt am Dateianfang stehen. (Achtung bei Copy & Paste des Beispiels)
Fehlerbehebung
Das obige Beispiel kann out of the Box funktionieren, muss aber nicht...
- Nach eigenen Ergänzungen des PHP-Scripts kontrollieren (je nach Hosting-Einstellungen) ob allfällige php-Fehler ausgewiesen werden und wo, hier hilft – sofern vorhanden – ein Blick in die Log-Meldungen von PHP.
- Wenn kein Fehler auftritt, aber nie eine Mail ankommt, sollte testweise eine andere Empfängeradresse verwendet werden.
- Auch kann der Mailserver je nach Konfiguration E-Mails ablehnen, wenn er nicht für die Absender-Adresse „zuständig“ ist. Der E-Mail-Server von selfhtml.org sollte beispielsweise keine E-Mails mit dem Absender tim.cook@apple.com akzeptieren.
- Bei Fehlermeldungen, die die Authentifizierung betreffen, sollten die Zugangsdaten überprüft werden. Gelegentlich reicht
nutzername
aus, manchmal muss auch die Domain mit angegeben (nutzername@example.org
) werden.
Weblinks
- Sending Emails with Mailer (symfony.com)
- PHPMailer eine andere Bibliothek, die ähnliches leistet wie Swift Mailer
- ↑ eRecht24.de: Impressumspflicht: E-Mail-Adresse oder Kontaktformular im Impressum?
- ↑ Symfony Mailer
- ↑ SELFHTML-Forum: (Erläuterung)
Information
Das Skript muss in eine eigene Datei gespeichert werden, z.B. mit Dateinamen formmailer.php, und sollte in UTF-8 abgespeichert werden (ohne BOM). Wenn Sie das HTML-Formular vom PHP-Script trennen möchten, müssen Sie im Formular unter
action
die Adresse des Scripts eintragen, ein leerer Eintrag sendet die Daten an die aktuelle URL.ToDo (weitere ToDos)
Swiftmailer wird seit dem Jahr 2021 nicht mehr gepflegt und sollte dringend durch eine Alternative ersetzt und nicht mehr in neuen Projekten verwendet werden!
Artikel muss überarbeitet werden! --Matthias Scharwies (Diskussion) 08:28, 4. Nov. 2022 (CET)