PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


IMAP-Emails lesen mit dem Zend Framework

with 5 comments

Emails werden nicht nur von Menschen für Menschen geschrieben, sie werden auch häufig zur asynchronen Kommunikation zwischen Rechnern und Programmen eingesetzt.

In der Vergangenheit habe ich bereits einige Scripte geschrieben die Emails periodisch abholen und bearbeiten. Darunter waren zum Beispiel Backup-Benachrichtigungen von einem Programm das früher nicht in der Lage war, die Ergebnisse in eine Datenbank zu schreiben. Um eine Übersicht über einen Zeitraum zu erhalten muß man die Ergebnisse also per Email in ein Postfach senden lassen und dieses periodisch abrufen und die Emails parsen.

Ein anderes Script hat zum Beispiel ein Postfach nach Anhängen durchsucht. Dieses Postfach wurde dazu benutzt, Dokumente automatisiert verarbeiten zu lassen. Dazu wurden die Emails geparst, die Anhänge gelöst und dann je nach Absender an einen bestimmten Sachbearbeiter gesendet oder an ein automatisiertes System weitergeleitet bzw. auf ein Netzwerklaufwerk abgelegt.

Es gibt noch viele weitere Möglichkeiten, wofür Emails nützlich sein können und warum man sie automatisiert verarbeiten sollte.

Früher habe ich diese Arbeit mit den imap_* Funktionen erledigt. Heutzutage nutze ich dafür natürlich die Zend-Framework Klassen Zend_Mail_Storage_Imap und Zend_Mail_Message. Der Zugriff via IMAP ist der POP3-Möglichkeit vorzuziehen, da wir dann z.B. Flags oder Ordner nutzen können um Mails zu markieren/verschieben die gerade in Progress sind bzw. fertig bearbeitet wurden.

Um eine Verbindung zum Mailserver aufzubauen nutzen wir einfach den Konstruktor:

$storage = new Zend_Mail_Storage_Imap(array(
    'host'     => 'imap.firma.de',
    'user'     => 'postfach@firma.de',
    'password' => 'passworthier'));

Eine verschlüsselte SSL oder TLS Verbindung ist natürlich auch möglich (hier SSL):

$storage = new Zend_Mail_Storage_Imap(array(
    'host'     => 'imap.firma.de',
    'user'     => 'postfach@firma.de',
    'password' => 'passworthier',
    'ssl'      => 'SSL'));

Nachdem die Verbindungsparameter spezifiziert wurden kann man nun auf den Server zugreifen. Als erstes möchten wir uns die Gesamtanzahl der Nachrichten im aktuellen Ordner anzeigen lassen:

echo $storage->countMessages() . ' Nachrichten im Ordner';

Mit Hilfe einer foreach-Schleife können wir nun alle Emails durchlaufen. Das ist möglich da das Storage-Object das Iterator-Pattern implementiert:

foreach ($storage as $messageNum => $message) {
    echo 'Email von '.$message->from.': '.$message->subject;
}

Wie man oben sehen kann werden die Header der Email einfach wie ein public Attribut abgefragt. Das wird intern über die magische __get() Funktion ermöglicht. Man kann aber auch die getHeader() Funktion nutzen, die gerade im Fall von „besonderen“ Headern wie „Reply-To“ einfacher einzusetzen ist ($message->reply-to wäre ungültig).

Um auf den Inhalt der Email zugreifen zu können nutzt man die getContent()-Funktion:

echo $message->getContent();

Da Emails aus mehreren Teilen bestehen können (Textteil, HTML-Teil, Anhänge, Inline-Bilder usw) kann man diese Teile auch untersuchen:

$foundPart = null;
foreach (new RecursiveIteratorIterator($message) as $part) {
    try {
        if (strtok($part->contentType, ';') == 'text/plain') {
            $foundPart = $part;
            break;
        }
    } catch (Zend_Mail_Exception $e) {
        // ignorieren
    }
}
if (!$foundPart) {
    echo 'kein reiner Text-Teil gefunden';
} else {
    echo "Reiner Text-Teil: \n" . $foundPart;
}

Auf IMAP-Servern können wir wie bereits erwähnt Emails mit Flags versehen und abfragen.

if ($message->hasFlag(Zend_Mail_Storage::FLAG_FLAGGED)) {
        continue;
}

Damit würden wie alle Emails überspringen die geflaggt sind. Flags können wie gesagt dafür genutzt werden um bereits bearbeitete Emails zu markieren.

$storage->setFlags($messageNum, array(Zend_Mail_Storage::FLAG_FLAGGED));

Man kann natürlich auch auf einzelne Emails zugreifen:

$message = $storage->getMessage($messageNum);

Dabei sollte man jedoch daran denken dass $messageNum die Sequenznummer ist. Wenn eine Email heute die Sequenznummer 3 hat, kann sie morgen schon die Sequenznummer 2 haben wenn Email 1 oder 2 in der Zwischenzeit gelöscht wurde.

Emails löschen ist auch sehr einfach:

$storage->removeMessage($messageNum);

Wie bereits geschrieben kann es dabei zu Verschiebungen der Sequenznummern kommen, es ist also Vorsicht geboten.

Die Zend-Framework-Klassen sind für die meisten einfachen Aufgaben sehr gut brauchbar. Wenn man allerdings erweiterte Funktionalitäten benötigt muß man die Klasse erweitern. Um einigen Problemen aus dem Weg zu gehen habe ich beispielsweise alle Funktionen erweitert, sodass ich mit UniqueIDs arbeiten kann statt Sequenznummern. Desweiteren sind folgende Funktionen dazugekommen die man des öfteren mal benötigt (für die meisten davon gibt es bereits Issue-Tracker-Einträge, um sie in das Framework aufzunehmen):

sort() Methode: http://framework.zend.com/issues/browse/ZF-9138
search() Methode: http://framework.zend.com/issues/browse/ZF-8858
Kopieren mehrere Emails mit einem IMAP-Befehl (nicht copy() in einer Schleife aufrufen): http://framework.zend.com/issues/browse/ZF-8513
Flags auf mehrere Emails gleichzeitig setzen (anstatt setFlags() in einer Schleife aufrufen zu müssen): http://framework.zend.com/issues/browse/ZF-8488
Mehr Kontrolle über den EXPUNGE Befehl: http://framework.zend.com/issues/browse/ZF-5655

Written by Michael Kliewe

März 12th, 2010 at 9:34 am

Posted in PHP

Tagged with , ,

5 Responses to 'IMAP-Emails lesen mit dem Zend Framework'

Subscribe to comments with RSS or TrackBack to 'IMAP-Emails lesen mit dem Zend Framework'.

  1. “ Nachrichten im Ordner; Mit Hilfe einer foreach-Schleife können wir nun alle Emails“ – was meinst du damit?

    wo kann ich

    12 Mrz 10 at 14:19

  2. @“wo kann ich“: Kannst du die Frage bitte etwas anders stellen? Verstehe sie nämlich nicht.

    Übrigens habe ich noch die Funktion vergessen mit der man den Ordner wechseln kann:

    $storage->selectFolder(‚INBOX‘);

    Wie man einen Ordner anlegt oder löscht findet man auch schnell im ZendFramework Manual.

    Michael Kliewe

    12 Mrz 10 at 14:42

  3. […] Zend Mail aus dem Zend Framework + diese Anleitung von PHP Gangsta […]

  4. Vielen Dank für die Infos! Die fehlende sort() methode hatte mir Kopfzerbrechen bereitet. Ich hab die, die du im Zend Issue Tracker verinkt hast verwendet.

    Übrigens evtl. hilfreich zu wissen:
    Der Parameter $sortBy muss im folgenden Format übergeben werden: „(SUBJECT REVERSE DATE)“

    laut: http://www.faqs.org/rfcs/rfc5256.html

    Karl

    10 Mai 11 at 16:05

Leave a Reply

You can add images to your comment by clicking here.