PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


Ein paar Zend_Mail Tricks

with 12 comments

Wer Mails verschickt, nutzt bei sehr einfachen (Admin) E-Mails meistens die eingebaute mail() Funktion. Sobald es aber darum geht komplexere E-Mails zu versenden wird man wahrscheinlich eine Klasse benutzten, die es einem einfacher macht, Anhänge anzuhängen, einen text/plain und einen text/html Teil mitzusenden, zusätzliche Empfänger zu definieren oder inline-Bilder gleich mit in die Email zu packen.

Es gibt dutzende gute Mail-Klassen und Libraries da draußen (ezcMail, htmlMimeMail5), ich benutze häufig Zend_Mail. Mit den verschiedenen Zend_Mail_Transport_* Klassen ist es möglich, die Mails über sendmail (sprich über mail()) zu versenden, oder aber beispielsweise mit Hilfe des SMTP-Protokolls an einen SMTP-Server zu übergeben. Seit wenigen Monaten neu ist Zend_Mail_Transport_File, womit die E-Mail nicht versendet wird, sondern „nur“ in eine Datei geschrieben wird. Ich habe mir früher einen solchen Adapter selbst geschrieben, nun ist er im Zend Framework enthalten.

Mit diesem Adapter ist es sehr einfach möglich, beispielsweise in der Entwicklungsumgebung keine E-Mails zu versenden, damit nicht aus Versehen beim Testen des Abschickens eines Formulars wirkliche E-Mails versendet werden, sondern nur zu Debuggingzwecken in eine Datei geschrieben wird. Beispielsweise so:

[production]
;    Config we use for production:
resources.mail.transport.type = smtp
resources.mail.transport.host = "smtp.example.com"
resources.mail.transport.auth = login
resources.mail.transport.username = myUsername
resources.mail.transport.password = myPassword

[development]
;    This options for the dev env:
resources.mail.transport.type = file
resources.mail.transport.path = "/tmp/send" 

Mit dem Adapter ist es auch möglich, den Mail-Versand zu testen mittels Unit-Tests, der Inhalt der Datei kann dann einfach gegen die erwartete Ausgabe geprüft werden.

In meinem eigenen Repertoire habe ich noch einen Adapter, mit dem man dieses Schreiben in eine Datei umgehen kann und den generierten E-Mail Quelltext direkt abfragen kann. Auch dieser Adapter kann natürlich gut zu Testzwecken genutzt werden, und man benötigt keinen Speicherplatz/Schreibrechte:

<?
class App_Mail_Transport_Null extends Zend_Mail_Transport_Smtp {
    /**
     * DON'T send an email via the SMTP connection protocol
     *
     * @return void
     */
    public function _sendMail()
    {
    }

    public function getSmtpMailSource()
    {
        if (empty($this->header)) {
            throw new Exception('Mail source could not be returned, you have to call send() first!');
        }

        return $this->header . Zend_Mime::LINEEND . $this->body;
    }
}

$transport = new App_Mail_Transport_Null();
$mail->send($transport);
$messageString = $transport->getSmtpMailSource();

Das Senden von vielen E-Mails wird kompliziert wenn man möglichst schnell möglichst viele E-Mails versenden möchte. Eine der schnellsten Methoden ist es, die generierte E-Mail in eine Datei zu schreiben und dann in das Pick-Up Verzeichnis des Postfix zu schieben. Dazu kann der oben gezeigte File-Adapter genutzt werden. Falls dieser Weg zu umständlich ist (oder kein Zugriff auf dieses Verzeichnis möglich ist), bleibt nur der Versand über SMTP. Aber auch da gibt es einige feine Unterschiede. Normalerweise wird für jede E-Mail eine eigene TCP/IP Verbindung geöffnet und dann für jede E-Mail ein SMTP-Dialog abgespult. Doch es geht auch effizienter, indem man eine Verbindung wiederbenutzt. Hier erstmal das normale Vorgehen:

$tr = new Zend_Mail_Transport_Smtp("mail.example.com")
Zend_Mail::setDefaultTransport($tr);

for ($i = 0; $i < 5; $i++) {
    $mail = new Zend_Mail();
    $mail->setBodyText("This is the text of the mail. $i");
    $mail->setFrom("sender@example.com", "Some Sender $i")
    $mail->addTo("recipient@example.com", "Some Recipient $i");
    $mail->setSubject("Test Subject $i");
    $mail->send();
}

Besser ist es jedoch so:

$tr = new Zend_Mail_Transport_Smtp("mail.example.com");
Zend_Mail::setDefaultTransport($tr);

$mail = new Zend_Mail();
for ($i = 0; $i < 5; $i++) {
    $mail->setBodyText("This is the text of the mail $i.");
    $mail->setFrom("sender@example.com", "Some Sender $i");
    $mail->addTo("recipient@example.com", "Some Recipient $i");
    $mail->setSubject("Test Subject $i");
    $mail->send();
}

Im zweiten Fall bleibt die Verbindung bestehen, und es wird im SMTP-Dialog einfach ein RSET gesendet und dann die nächste E-Mail verschickt.

Bei dieser Methode gilt jedoch zu beachten dass viele SMTP-Server die Anzahl der E-Mails, die innerhalb eines SMTP-Dialogs versendet werden dürfen, beschränken.

Written by Michael Kliewe

April 5th, 2011 at 9:18 am

Posted in PHP

Tagged with ,

12 Responses to 'Ein paar Zend_Mail Tricks'

Subscribe to comments with RSS or TrackBack to 'Ein paar Zend_Mail Tricks'.

  1. Danke, das mit dem Zend_Mail_Transport_File war mir neu, aber mir fallen da auf anhieb ein paar Projekte ein, die damit _bedeutend_ einfacher zu debuggen sind 😉

    Sascha Presnac

    5 Apr 11 at 10:07

  2. Zend_Mail_Transport_File ist ein Segen auf Development-Systemen. An Stellen, wo ich Zend_Mail nicht verwende, sondern auf die altehrwürdige mail() Funktion zurückgreife, benutze ich ein Shellskript und eine veränderte Einstellung von sendmail_path in der php.ini:

    http://shiflett.org/blog/2007/dec/php-advent-calendar-day-1

    Gabriel

    5 Apr 11 at 10:41

  3. @Gabriel: Jetzt hast du mir doch glatt einen meiner nächsten Artikel vorweggenommen 😉 Hier gibt es noch weitere Informationen darüber:
    http://seancoates.com/blogs/mail-replacement—-a-better-hack

    Michael Kliewe

    5 Apr 11 at 10:55

  4. Auch wenn thematisch nicht ganz passt, zum Testen (manuell nicht Unit test) verwende ich gerne SMTP4DEV, das kleine Tool spielt Mailserver und man kann sich die Mails im „Original“ betrachten. Sicher gibt es eine Menge richtige kostenlose Server, aber das Teil hat mich durch die Einfachheit vollkommen überzeugt.

    http://smtp4dev.codeplex.com/

    Arne Riemann

    5 Apr 11 at 12:44

  5. Anfangs benutzte ich auch „log files“ für die Mails, aber als man mir jemand vor paar Monaten smtp4dev vorstellte war ich helauf begeistert (aus den gleichen gründen wie Arne => einfach & schnell 🙂 )

    ragtek

    5 Apr 11 at 15:56

  6. Für Windows User eventuell interessant, aber für ein Team, wo der eine Mac, der andere Linux und der dritte Windows nutzt, keine wirkliche Lösung, da kommt man wohl um Logfiles nicht herum.

    Der Vorteil eines vollständigen Dummy-Servers ist aber, dass auch der SMTP-Dialog durchgespielt wird, beim File-Transport findet der nicht statt, es könnten also Fehler übersehen werden.
    Es gibt aber mit Sicherheit auch einen ähnlichen Dummy-Server für Linux/Mac, der ein rudimentäres SMTP-Protokoll spricht und die Mail in eine Datei schreibt. Könnte man sogar schnell in PHP zusammenschustern.

    Michael Kliewe

    5 Apr 11 at 17:45

  7. ================
    Für Windows User eventuell interessant,
    ================
    hab vergessen zu erwähnen,dass das einer der Hauptgründe für mich war^^
    Bin einer der wenigen reinen Win7 Arbeits PC Benutzer:)

    ragtek

    5 Apr 11 at 18:19

  8. Wichtig ist auch beim Erstellen des Zend_Mail-Objektes die Codierung auf UTF-8 zu stellen, andernfalls fickts die Umlaute und Sonderzeichen. Intern arbeitet Zend_Mail nämlich iso…

    Stürmer

    5 Apr 11 at 18:19


  9. Bin einer der wenigen reinen Win7 Arbeits PC Benutzer:)

    *puh* … und ich dachte schon, ich bin der einzige, der ausschließlich mit Windows arbeitet 😉

    Sascha Presnac

    5 Apr 11 at 19:25

  10. Ich werde immer ausgelacht/schief angeschaut wenn ich das erwähne..:D

    Aber ja…

    ragtek

    5 Apr 11 at 19:54

  11. Zuhause nutze ich auch Windows, weil ein Browser dort genauso funktioniert wie unter Mac/Linux und die IDE auch nutzbar ist, und ich brauche für Spiele nicht umloggen 😉

    Aber ich nutze wenn es geht keine Programme, die nur unter Windows einsetzbar sind, weil ich dann in der Firma oder auf dem Server, wo phpUnderControl läuft, eine Alternative bräuchte, also warum nicht gleich die Alternative überall nutzen 😉 Eine Shell ist sowieso permanent offen, da kann man dann auch ein tail laufen lassen wenn man die Mails in Echtzeit angucken möchte, die in die Datei geschrieben werden.

    Michael Kliewe

    5 Apr 11 at 20:01

  12. Tail, grap & co benutze ich auch unter Win (die Tools wird wohl jeder kennen) aber DAS NON PLUS ULTA „ohne das ich nicht mehr kann“, aber kaum jemand kennt sind die symlinks unter win http://blogs.ragtek.org/webdeveloper/allgemein/symlinks-unter-windows-mklink-vs-ln/

    ragtek

    5 Apr 11 at 20:09

Leave a Reply

You can add images to your comment by clicking here.