Poststelle automatisiert

Gegenüber POP3 bietet das Mailprotokoll IMAP etliche Vorzüge. Diese lassen sich nicht nur per Mail-Client sondern auch in Scripts nutzen - zum Suchen, für Statistiken oder bei der Anbindung von RSS-Quellen.

In Pocket speichern vorlesen Druckansicht 2 Kommentare lesen
Lesezeit: 7 Min.
Von
  • Nathanael Obermayer
Inhaltsverzeichnis

Zunehmend lösen IMAP-basierte Dienste alte POP3-Server ab. Neben dem einfachen Mail-Abruf bietet IMAP viele weitere Funktionen, etwa das Speichern der Nachrichten in einer flexiblen Ordnerstruktur auf dem Server. Diese „Folder“ lassen sich nach vielfältigen Kriterien serverseitig durchsuchen. Wie üblich finden sich in der Perl-Welt viele Module zum Zugriff auf IMAP-Server. Besonders ausgereift und stabil ist Mail::IMAPClient von David J. Kernen. Es implementiert nahezu alle IMAP-Funktionen und eignet sich daher hervorragend zum Entwickeln eigener Lösungen. Drei kleine Beispiele illustrieren dies im Folgenden: die gemeinsame Nutzung von RSS-Quellen, die Erzeugung von Diagrammen mit statistischen Daten und das Durchsuchen von Mails auf dem Server.

Durch die im IMAP-Protokoll vorgesehene Ordnerstruktur auf dem Server kann der Anwender seine E-Mails sortiert speichern. Im Prinzip darf diese Ordnerstruktur jedoch beliebige Daten aufnehmen. Der Anwender greift auf sie über eine ihm bekannte Oberfläche - sein E-Mail-Programm - zu. Daten, die sich zur zentralen Speicherung in einem IMAP-Server eignen, sind beispielsweise Bookmarks oder RSS-Feeds.

Zusätzlich bieten einige IMAP-Server gemeinsam genutzte Ordner (shared folders). In ihnen speichern sie die Daten einmalig, die zugehörigen Metadaten jedoch für jeden einzelnen Anwender getrennt. Dazu gehört beispielsweise das „Seen“-Flag, das kennzeichnet, ob ein Anwender eine bestimmte E-Mail gelesen hat. So lassen sich beispielsweise populäre RSS-Feeds einmal herunterladen und von vielen Anwendern gemeinsam nutzen. Wie sich so etwas per Perl-Skript implementieren lässt, zeigen die folgenden Zeilen.

Das CPAN-Modul XML::RSS ermöglicht das Parsen von RSS-Feeds. Die eigentliche RSS-Datei kann man mit dem Modul LWP::Simple herunterladen:

use LWP::Simple qw(get);
my $rss_document = get($feed->{ url })
or die 'Konnte die Datei nicht herunterladen';
my $xmlrss = new XML::RSS;
$xmlrss->parse($rss_document);

Zur Repräsentation von IMAP-Verbindungen dienen Objekte der Klasse Mail::IMAPClient. Beim Erzeugen des Objekts lässt sich die Serververbindung so aufbauen:

my $imap = Mail::IMAPClient->new(
Server => HOST,
User => USERNAME,
Password=> PASSWORD,
) or die "Verbindungsaufbau nicht möglich: $@";

Jede RSS-Quelle soll der Server in einem eigenen Ordner speichern. Sofern dieser noch nicht existiert, kann man ihn automatisch anlegen:

$imap->create($imapfolder) or die $!
unless $imap->exists($imapfolder);
$imap->select($imapfolder);

Normalerweise enthält eine RSS-Quelle ein bis fünfzehn „Items“ genannte Teile. Das sind beispielsweise aktuelle Nachrichten oder Blog-Einträge. Da das Skript die RSS-Feeds in regelmäßigen Abständen abfragt, muss es prüfen, ob ein bestimmtes Item schon vorhanden ist. Dies kann das search-Kommando erledigen:

my $subject = $item->{ title };
my @ids = $imap->search("SUBJECT ".$imap->Quote($subject));
return if (@ids > 0);

Es ist einer der optionsreichsten und mächtigsten Befehle des IMAP-Protokolls und dient zur serverseitigen Suche. Zusätzliche Bedingungen (so genannte Keys) können die Ergebnismenge Schritt für Schritt einschränken, beispielsweise durch Angabe des Betreffs oder bestimmter Wörter innerhalb der Nachricht. Hierzu definiert der IMAP-Standard verschiedene Schlüsselwörter wie SUBJECT, KEYWORD, SINCE und BEFORE, oder Flag-bezogene wie SEEN und DELETED.

DELETED markiert gelöschte E-Mails, die nach dem IMAP-Protokoll zunächst auf dem Server bleiben. Daher kann der Anwender einzelne RSS-Nachrichten löschen, ohne deren Feed-Eintrag beim nächsten Abruf erneut zu erhalten. Ist ein Item im gewählten Ordner noch nicht vorhanden, wandelt das Skript den Text mit Hilfe des Moduls Mail::Message zu einer standardkonformen E-Mail und fügt sie dem gewählten Ordner hinzu.

my $message = Mail::Message->buildFromBody(
$body,
From => '{RSS}',
To => 'reader@example.com',
Subject => $subject
);
$imap->append($imapfolder,$message->string);

Ab jetzt muss der Anwender nur noch den Ordner in seinem E-Mail-Client abonnieren, dann kann er auf die einzelnen Items der Quelle zugreifen.

Da das Modul Mail::IMAPClient den Zugriff auf alle gespeicherten Nachrichten ermöglicht, ist es sehr leicht, Statistiken über Mail-Aufkommen oder Nachrichtenqualität (beispielsweise Verhältnis aller Mails zur Anzahl der Mails im Spam-Order) zu erstellen. Daraus lassen sich mit Hilfe des neuen Moduls SWF::Chart Flash-basierte Grafiken erzeugen. Es ist die Perl-Portierung der „PHP/SWF Charts“-Software. Die 0.01-Version gibt es auf der Website des Autors (nathan.torkington.com/tmp/SWF-Chart-0.01.tar.gz). Wie üblich, erfolgt die Installation durch

perl Makefile.pl
make
make test
make install

wobei der letzte Schritt Root-Rechte erfordert. Das Modul erzeugt HTML-Code, der ein Flash-Applet lädt und mit allen notwendigen Parametern konfiguriert. Das Darstellen der Diagramme übernimmt dieses Applet.

Um beispielsweise eine Übersicht über die Anzahl der Mails in den verschiedenen Foldern zu erstellen, erfragt ein Skript zuerst alle Ordner vom Server. Für jeden von ihnen ermittelt es im nächsten Schritt die Anzahl der enthaltenen Mails und speichert diesen Wert in einem Hash unter dem Schlüssel chart_data. Im selben Hash legt chart_type das Aussehen des Diagramms fest. Beispiele für die verschiedenen Möglichkeiten finden sich unter www.maani.us/charts/index.php?menu=Gallery. Ein dreidimensionales Tortendiagramm etwa erzeugt man durch

my $chartdata = {
chart_type => '3d pie',
chart_data => [[''], [''] ]
};
foreach my $foldername ($imap->folders) {
my $number_of_messages =
$imap->message_count( $foldername );
push @{$chartdata->{ chart_data }->[0]},
$foldername;
push @{$chartdata->{ chart_data }->[1]},
$number_of_messages;
}

Unterhalb des Schlüssels chart_data werden in zwei Arrays die Bezeichnungen der einzelnen Tortenstücke (Foldernamen) sowie die zugehörigen Werte gespeichert. Ähnlich entsteht eine Übersicht über den Platzbedarf der gespeicherten Mails, etwa in Form eines Balkendiagramms, das alle Nachrichten nach Größenklassen sortiert darstellt.

Sind sämtliche Daten in den Hash geschrieben, gibt DrawChart den gewünschten HTML-Code aus. Dieser erwartet die Datei charts.swf im selben Verzeichnis. Sie ist unter www.maani.us/charts zu finden.

Mitten aus dem wirklichen Leben stammt ein weiteres Beispiel für den Einsatz des Moduls. Beim Versand von Mails an Teilnehmer einer Liste gab es immer wieder Rückläufer. Diese lassen sich beispielsweise per procmail-Script in einem eigenen IMAP-Folder namens failed sammeln. Ein wenig Perl-Code sucht aus diesem Folder die fehlerhaften Empfängeradressen heraus (s. Listing).

Mehr Infos

Listing 1: Rückläufer auswerten

Mit wenigen Zeilen Perl-Code lassen sich alle Nachrichten in einem IMAP-Ordner nach einem bestimmten Muster durchsuchen.

$imap->select($top_level .
$imap->separator()."failed");
foreach my $m (1..$imap->message_count) {
my $b = $imap->body_string($m);
my ($to) = grep /^To:.*$/, split (/\r\n/,$b);
$to =~ s/^To: //;
if ($to =~ /=\?ISO/i) {
$to =~ s/=([A-F0-9][A-F0-9])/chr(hex($1))/eg;
$to =~ s/_/ /g;
$to =~ s/=\?ISO-8859-1\?Q\?//gi;
$to =~ s/\?=//g;
}
print "$to\n";
}

An diesen Zeilen ist zu erkennen, wie man alle Nachrichten innerhalb eines IMAP-Ordners verarbeitet. Dazu reicht es, die Anzahl zu ermitteln (message_count()) und anschließend jede Nachricht abzurufen. Die Methode body_string() liefert den eigentlichen Text. separator() ermittelt das Trennzeichen für Folderhierarchien. Am meisten Aufwand erfordert das Herausfischen der Adressen und das Wandeln von Umlauten in den Empfängernamen. Die vollständigen Quellen der Beispiele finden sich auf dem FTP-Server der iX.

Nathanael Obermayer
arbeitet bei der Entropia Software GmbH als Senior Developer.
(ck)