PHP/Anwendung und Praxis/Formmailer-Advanced

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Inhaltsverzeichnis

[Bearbeiten] Hinweise zum Thema

Es gibt die Möglichkeit, HTML-Formulare durch ein mailto: im action-Attribut per E-Mail zu versenden. Allerdings ist diese Methode nicht sonderlich zuverlässig, da sie vom Browser des Benutzers abhängig ist.

Deshalb wird an dieser Stelle ein fortgeschrittener Formmailer vorgestellt, der den größten Teil seiner Mächtigkeit durch den Einsatz einer auf diesen Einsatzzweck spezialisierten Bibliothek erreicht. Selbstverständlich ist die Bibliothek Open Source (LGPL-Lizenz), die Mindestversion ist PHP 5.2.

Die hier verwendete Bibliothek heißt SwiftMailer und 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.[1]

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


[Bearbeiten] Beispiel mit Erläuterungen

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

Um die Vergleichbarkeit mit dem "einfachen PHP-Mailer" zu behalten, wird hier dasselbe Formular verwendet.

[Bearbeiten] Notwendige Vorbereitungsarbeit

  1. Laden Sie die Bibliothek "SwiftMailer" von der Adresse http://swiftmailer.org herunter.
  2. Entpacken Sie die Downloaddatei und kopieren Sie die Bibliothek so, dass parallel zur Datei des Formmailers ein Unterverzeichnis namens Swift-4.0.7 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.


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.com';  
 
 // Welche Adresse soll als Absender angegeben werden?
 // (Manche Hoster lassen diese Angabe vor dem Versenden der Mail ueberschreiben)
 $absenderadresse = 'ihrAndererName@EXAMPLE.com'; 
 
 // 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 muessen hier eine gueltige HTTP-Adresse angeben!
 $urlDankeSeite = 'http://www.EXAMPLE.com/IhrName/IhreSeite.htm'; 
 
 // Welche(s) Zeichen soll(en) zwischen dem Feldnamen und dem angegebenen Wert stehen?
 $trenner = ":\t"; // Doppelpunkt + Tabulator
 
 /** 
  * Ende Konfiguration
  */ 
 
 require_once "Swift-4.0.7/lib/swift_required.php"; // Swift initialisieren
 
 if ($_SERVER['REQUEST_METHOD'] === "POST") {
 
     $message = Swift_Message::newInstance(); // Ein Objekt für die Mailnachricht.
 
     $message
         ->setFrom(array($absenderadresse => $absendername))
         ->setTo(array($zieladresse)) // alternativ existiert setCc() und setBcc()
         ->setSubject($betreff);
 
     $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');
 
     $mailer = Swift_Mailer::newInstance(Swift_MailTransport::newInstance());
     $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 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de">
     <head>
         <title>Einfacher PHP-Formmailer</title>
         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     </head>
     <body>
         <h1>Beispielformular</h1>
         <form action="" method="post">
             <!-- Hier die eigentlichen Formularfelder eintragen. Die folgenden sind Beispielangaben. -->
             <dl>
                 <dt>Ihr Name:</dt>
                 <dd><input type="text" name="Versender" /></dd>
                 <dt>Ihre E-Mail:</dt>
                 <dd><input type="text" name="E-Mail" /></dd>
                 <dt>Sie können:</dt>
                 <dd><input type="checkbox" name="kannwas[]" value="HTML" />HTML <input type="checkbox" name="kannwas[]" value="PHP" />PHP</dd>
                 <dt>Sie sind:</dt>
                 <dd><input type="radio" name="sexus" value="M" />Mann <input type="radio" name="sexus" value="Frau" />Frau</dd>
                 <dt>Sie mögen:</dt>
                 <dd><select name="Browser"><option value="Opera">Opera</option><option value="Mozilla">Mozilla</option></select></dd>
                 <dt>Bemerkungen:</dt>
                 <dd><textarea name="Bemerkungen" rows="3" cols="20">Bemerkungen</textarea></dd>
             </dl>
             <!-- Ende der Beispielangaben -->
             <p>
             <input type="submit" value="Senden" />
             <input type="reset" value="Zurücksetzen" />
             </p>
         </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.

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 "PHP-Funktion mail()" 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.

[Bearbeiten] Vorteile von SwiftMailer gegenüber der einfachen Variante

Auf den ersten Blick sind die Vorteile gegenüber einem einfachen PHP-Mailer nicht sofort sichtbar. Der Code des fortgeschrittenen Mailers ist weder kürzer, noch anders strukturiert.

Die Vorteile liegen aber im Detail. Beachten Sie beispielsweise, dass beim einfachen Formmailer Funktionen zum korrekten Escaping der Stringwerte für den Betreff und die Absenderadresse benutzt werden müssen. Dies wird von Swiftmailer automatisch richtig gehandhabt. Ebenso ist bei SwiftMailer 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 ist die Möglichkeit, den Mailtransport leicht umzukonfigurieren. Die Funktion mail() von PHP 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. SwiftMailer bietet zusätzlich zur Nutzung der Funktion mail() noch den Versand direkt über den Unix-Befehl sendmail (damit wird direkt der installierte System-Mailserver kontaktiert) und den Versand über einen erreichbaren SMTP-Mailserver (insbesondere interessant für Windows-Systeme, die kein sendmail kennen, aber auch für Unix-Server, bei denen man das lokale Mailsystem nicht benutzen will).

Seine Stärken voll ausspielen kann SwiftMailer, 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.

Beispiel: 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 SwiftMailer schon etwas aufwendiger - ohne SwiftMailer allerdings kommt man um ein intensives Studium der einschlägigen RFC nicht herum.

Mit SwiftMailer 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 Cut&Paste des Beispiels)
Das Skript geht davon aus, dass PHP auf dem Server zeitgemäß ohne magic_quotes_gpc konfiguriert ist. Wenn dies nicht der Fall ist, werden eingegebene Anführungszeichen des Benutzers mit vorangestelltem Backslash in die Mail geschrieben. Sprechen Sie ggf. ihren Provider an, um dieses lästige Problem abschalten zu lassen.

Das Skript nutzt konsequent UTF-8 als Zeichencodierung. Denken Sie daran, diese Codierung nicht zu zerstören - andernfalls werden Umlaute im Text nicht korrekt dargestellt.

[Bearbeiten] weitere Tests

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

  • Nach eigenen php Ergänzungen kontrollieren (je nach Hostingeinstellungen) ob allfällige php-Fehler ausgewiesen werden und wo, nicht überall ist ein php-logging eingeschaltet.
  • Wenn kein Fehler, aber nie eine Mail ankommt, empfiehlt es sich testhalber auch eine andere Empfängeradresse zu verwenden.
  • Auch kann es Probleme geben, wenn Absender Adresse und Mailserver sich nicht vertragen.
  • Bei Verwendung von transport SMTP gibt der "logger" genau Aufschluss, ob die Mail korrekt gesendet werden konnte. (Verwendung von php-Mail wie in ursprünglichem Beispiel ergibt keine Aufschlüsse).
Beispiel
 // Code Ergänzungen: try und catch, logger
 // gemäss: [http://swiftmailer.org/pdf/Swiftmailer.pdf Swiftmailer.pdf]
 
 try {
     /* Mit try und catch können die Fehlerevents differenzierter getestet werden
     *
     * diverse Möglichkeiten für $Transport 
     * smtp mit den gewohnten Optionen, siehe Dokumentation Swiftmailer  
     *  für TLS und SSL  allenfalls phpinfo ob extentiens installiert
     */
 
     $Transport0 = Swift_MailTransport::newInstance();        /* Beispiel geht über PHP-Mail, geht i.a. 
                                                                 aber keine Information von logger     */
 
     $Transport = Swift_SmtpTransport::newInstance('smtp.our_url.ch',25,'tls' )     /* 'tls', Ports je nach Server */
      ->setUsername("our_user@our_url.ch")
      ->setPassword("our_passwd")
     ;
 
     $Transport2 = Swift_SmtpTransport::newInstance('mail.our_second.ch',25,'tls' )  /* 'tls' */
      ->setUsername("...")
      ->setPassword("...")
     ;
 
     $mailer = Swift_Mailer::newInstance($Transport); 
 
     // Echo Logger aktivieren (es gibt noch einen logger der auf File schreibt)
     $logger = new Swift_Plugins_Loggers_EchoLogger();
     $mailer -> registerPlugin ( new Swift_Plugins_LoggerPlugin ( $logger));
 
     $result = $mailer->send($message);
 
    }
     catch(Exception $e){
       $error_log = $logger->dump();
    }
Beachten Sie: Es gibt in der Download Version ein Problem mit dem "Base64ContentEncoder". Wer eine PDF mitschicken möchte, muss dieses Update einspielen:[2] https://github.com/swiftmailer/swiftmailer/blob/master/lib/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php#L34-L35

[Bearbeiten] Weblinks

  1. SwiftMailer
  2. selfhtml.forum: UPDATE: Swift Mailer
Meine Werkzeuge
Namensräume

Varianten
Aktionen
Übersicht
Index
Mitmachen
Werkzeuge
Spenden
SELFHTML