Ausbreitung des Coronavirus führt zu immer mehr Tafel-Schließungen

Um 1,6 Millionen bedürftige Tafel-Nutzer:innen jetzt nicht allein zu lassen, ruft Tafel Deutschland e.V. zu Solidarität und Unterstützung auf. Sie wollen helfen? Informationen finden Sie unter tafel.de.

Coronacharityshop.png

Eine weitere Möglichkeit ist der Einkauf im CoronaCharityShop – alle Einnahmen gehen zu 100 % an die Tafeln. Herzlichen Dank für Ihre Unterstützung.

PHP/Tutorials/Formmailer mit Swift Mailer

Aus SELFHTML-Wiki
< PHP‎ | Tutorials
Wechseln zu: Navigation, Suche

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 einen 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 Swift Mailer erreicht. Swift Mailer ist Open Source (MIT-Lizenz), PHP muss mindestens in Version 7.2 vorhanden sein.

Die hier verwendete Bibliothek Swift Mailer 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.

Swift Mailer hält sich an gute, etablierte Standards hinsichtlich der Benennung von Klassennamen (bekannt als PSR-0-kompatibel) und ist deshalb zu empfehlen.

Notwendige Vorbereitungsarbeit[Bearbeiten]

Swift Mailer ist eine Bibliothek, kein gebrauchsfertiges Programm, deshalb ist es notwendig, einige wenige Schritte vorzunehmen, um eine Mail abzusenden.

  1. Laden Sie Swift Mailer mittels Composer (composer require "swiftmailer/swiftmailer:^6.0") oder alternativ als ZIP-Archiv von GitHub herunter.
  2. Im Falle des händischen Downloads müssen Sie noch das Archiv entpackten und den Inhalt so kopieren, dass parallel zur Datei des Formmailers ein Unterverzeichnis namens swiftmailer-6.2.3 angelegt wird, in dem seinerseits das Verzeichnis lib der Bibliothek steckt. Sie können den Pfad aber im Prinzip beliebig an ihre Erfordernisse anpassen, sofern Sie die Einbindung im Formmailer in gleicher Weise anpassen.
  3. 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.


Beispiel
Bitte passen Sie die Werte aus dem Beispiel an Ihre Gegebenheiten an, bevor Sie das Script benutzen! 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.
<?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 abhängig von der Installationsmethode einbinden:
 // Falls Swift Mailer nicht über Composer installiert wurde:
 //require_once "swiftmailer-6.2.3/lib/swift_required.php";

 // Swift Mailer wurde über Composer installiert:
 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_MailTransport();

     $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.

Beachten Sie: Wenn Sie dieses Formular nicht öffentlich im Internet zur Verfügung stellen, beispielsweise durch durch Verwendung eines Zugriffsschutzes oder durch Trennung des Netzes vom Internet, müssen Sie Schutzmaßnahmen gegen Cross Site Request Forgery ergreifen.
Steht dieses Formular öffentlich im Internet zur Verfügung, beispielsweise als Kontaktformular, so ist ein Token-basierter Schutz gegen CSRF sinnvoll, wenn man auch eine Reloadsperre zu realisieren.

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 der Benutzung Swift Mailer gegenüber Eigenbaulösungen[Bearbeiten]

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 nicht 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 Swift 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 Live-Server 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. Swift 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). 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.

für das Anhängen eines Attachments
 $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.

Beachten Sie:

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)

Das Skript nutzt konsequent UTF-8 als Zeichencodierung. Denken Sie daran, besonders beim Speichern des Skripts diese Codierung zu verwenden – andernfalls werden beispielsweise Umlaute im Text nicht korrekt dargestellt.

Fehlerbehebung[Bearbeiten]

Das obige Beispiel kann out of the Box funktionieren, muss aber nicht...

  • Nach eigenen Ergänzungen des PHP-Scripts kontrollieren (je nach Hostingeinstellungen) 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 sie Zugangsdaten überprüft werden. Gelegentlich reicht nutzername aus, manchmal muss auch die Domain mit angeben (nutzername@example.org) werden.

Weblinks[Bearbeiten]

  1. eRecht24.de: Impressumspflicht: E-Mail-Adresse oder Kontaktformular im Impressum?