Webmailer mit PHP
Mobile E-Mail

DeveloperIT-ProjekteSoftware

Mit einem Webmailer prüfen Sie auch unterwegs schnell Ihre E-Mails und können zeitnah darauf reagieren. Internet Professionell zeigt, wie Sie selbst einen Webmailer mit PHP programmieren.

Werbefreier Eigenbau

Webmailer mit PHP

Sei es nun GMX, Web.de oder Hotmail ? es gibt viele Freemail-Anbieter, bei denen Sie kostenlos eine Menge Speicherplatz, mehrere E-Mail-Adressen und viele Funktionen erhalten, im Gegenzug aber eine Menge Werbung akzeptieren müssen. Die Oberflächen sind in der Tat jedoch durchgängig gut gestaltet, übersichtlich und mit allerlei Nützlichem gespickt. Doch was machen Sie, wenn Sie eine Mail-Adresse haben, die zu einer eigenen Domain gehört? Vielleicht möchten Sie unterwegs ebenfalls die Vorzüge eines Web.de genießen können. Und wenn es nun nicht eine, sondern mehrere Adressen sind? Es gibt kostenlose Webmailer im Internet an jeder Ecke, und auch viele Webhoster wie 1&1 und Hosteurope bieten ihren Kunden entsprechende Dienste an. Jedoch entsprechen diese nicht immer dem Anforderungsprofil. Also heißt es selbst Hand anlegen und den Webmailer nach Maß zu programmieren. Und ein weiterer Vorteil: Sie können damit über jeden SMTP-Server versenden.


Die imap-Bibliothek

Webmailer mit PHP

PHP stellt seit jeher eine Menge an Bibliotheken zur Verfügung, und wenn die benötigte einmal nicht dabei ist, wird man spätestens im PEAR oder PECL fündig. Für den Zugriff auf POP3- und IMAP-Postfächer gibt es jedoch von Haus aus bereits eine passende Bibliothek: php_imap. Um diese einsetzen zu können, müssen Sie sie aller Wahrscheinlichkeit nach noch aktivieren. Bei einer PHP-Installation unter Windows verändern Sie dazu folgende Zeile:

;extension=php_imap.dll

Entfernen Sie das Semikolon am Anfang der Zeile. Anschließend stehen die Funktionen der entsprechenden Bibliothek zur Verfügung.


Verbindung aufbauen

Webmailer mit PHP

Bevor Sie nun auf ein Postfach zugreifen können, müssen Sie mittels imap_open zunächst eine Verbindung herstellen:

int imap_open(string mailbox, string username, string password)

Ein wenig trickreich ist dabei der String, mit dem Sie der Funktion klar machen müssen, auf welchem Server der POP3- oder IMAP-Dienst läuft. Dazu wird für POP3 folgendes Format verwendet:

{/pop3: }INBOX

Handelt es sich um eine IMAP-Mailbox, muss an Stelle von pop3 entsprechend imap notiert werden:

{/imap: }INBOX

Vielleicht fragen Sie sich nun, was daran so trickreich sein soll. Es gibt jedoch ein kleines Detail, das in der Dokumentation selbst mit keiner Silbe erwähnt wird: Vor der öffnenden geschwungenen Klammer muss noch ein Backslash notiert werden. Der Aufruf der Funktion sieht also wie folgt aus:

$con = imap_open("\{$host/pop3:$port} INBOX",$boxname,$password);

Konnte eine Verbindung erfolgreich hergestellt werden, liefert die Funktion ein Handle zurück, das an alle nachfolgenden Funktionen, die auf die Mailbox zugreifen sollen, übergeben werden muss. Andernfalls ist das Ergebnis false.


E-Mails in der Übersicht

Webmailer mit PHP

Nachdem diese erste Hürde genommen ist, können Sie nun beginnen, eine Liste der in der Mailbox vorhandenen E-Mails auszugeben. Zunächst benötigen Sie dazu die genaue Anzahl der Mails. Diese ermittelt Ihnen die Funktion imap_num_msg. Als einzigen Parameter müssen Sie der Funktion das Verbindungs-Handle übergeben:

$msg_cnt = imap_num_msg($con);

Diesen Wert benötigen Sie, um die so genannte Sequenz zu definieren. Mit dieser legen Sie fest, zu welchen Mails in der Mailbox Informationen abgerufen werden sollen. Dabei werden der Anfangs- und Ende-Index durch einen Doppelpunkt getrennt zusammengesetzt. Alternativ könnten Sie mehrere einzelne Indizes verwenden, die dann durch ein Komma getrennt werden müssten. Befinden sich in einer Mailbox beispielsweise fünf Nachrichten, dann lautet die Sequenz für alle E-Mails 1:5. Das Verbindungs-Handle und die Sequenz müssen Sie anschließend der Funktion imap_fetch_overview übergeben:

$overview = imap_fetch_overview($con, $sequence);

Das Objekt, welches die Funktion zurückgibt, enthält nun Detailinformationen zu den Mails, wie etwa den Betreff, den Absender, das Datum oder die Größe in Bytes. Mit einer einfachen foreach-Schleife können diese Informationen ausgegeben werden:

foreach($overview as $o)
{
echo '
';

echo ' '.$o->from.'

';
echo ' '.$o->subject.'

';
echo ' '.$o->date.'

';
echo '

';
}

Aber auch hier kann es zu einem Problem kommen: Die Ausgabe könnte ein wenig unschön aussehen. Zumindest dann, wenn im Absender oder im Betreff ein Sonderzeichen verwendet wurden wie ä, ö, ü oder ß. Diese sind dann normalerweise UTF8-kodiert und müssen, der besseren Lesbarkeit zuliebe, dekodiert werden. Für diese Fälle können sie den folgenden Workaround verwenden.

if(strpos($o->subject,'?iso-8859-1?Q?') != false)
{
$subject = utf8_decode(imap_utf8($o->subject));
}

Nachdem die Ausgabe der Übersicht abgeschlossen ist, sollten Sie die Verbindung mittels imap_close beenden. Übergeben Sie der Funktion dazu das Verbindungs-Handle. Falls Sie die Verbindung nicht schließen, bleibt sie so lange aktiv, bis der serverseitig eingestellte Timeout greift. Solange die Verbindung offen ist, können Sie nicht auf die Mailbox zugreifen.


Abrufen von E-Mails

Webmailer mit PHP

Eine einfache Übersicht der Nachrichten ist zwar praktisch, freilich will man die einzelnen E-Mail-Nachrichten aber auch lesen. Um dies zu ermöglichen, stehen Ihnen bei PHP drei Funktionen zur Verfügung, welche Ihnen unterschiedliche Daten zurückliefern.

Die Funktion imap_headerinfo liest die Informationen des Nachrichten-Headers ein und gibt diese als Objekt zurück, wohingegen imap_fetchstructure Daten zur Struktur der Mail liefert ? ebenfalls als Objekt. Die Dritte im Bunde ist imap_fetchbody, welche den Body einer bestimmten Nachricht zurückliefert.

Den Betreff der E-Mail, den Absendernamen sowie die Absenderadresse liefert Ihnen imap_headerinfo. Der Funktion müssen Sie das Verbindungs-Handle und den Nachrichtenindex übergeben:

$info = imap_headerinfo($con,$index);
$subject = $info->subject;
$from = $info->from[0]->personal;
$fromemail = $info->from[0]->mailbox.'@'.$info->from[0]->host;


Nachrichten ausgeben

Webmailer mit PHP

Bei der Ausgabe des Nachrichtentextes wird es wieder ein wenig kompliziert. Denn eine Mail, wie sie heutzutage verschickt wird, besteht nicht mehr nur aus Text, sondern kann in HTML formatiert sein und verschiedene Dateianhänge besitzen. Auch die Kodierungsmöglichkeiten sind vielfältig. Um zu ermitteln, wie eine E-Mail kodiert wurde, brauchen Sie die imap_fetchstructure-Funktion. Die Art der Kodierung ist in der Eigenschaft encoding hinterlegt. Wie die Dekodierung erfolgen kann, finden Sie in den Listings view.php und standard.lib.php auf der Heft-CD.

Die Nachricht selbst wird wie erwähnt mit imap_fetchbody ausgelesen. Als Parameter erwartet die Funktion das Verbindungs-Handle und den Index der Nachricht. Außerdem müssen Sie angeben, welchen Teil der Nachricht Sie auslesen möchten. In der Regel ist der Nachrichtentext der erste Teil der Nachricht, während die Anhänge die darauf folgenden Teile bilden:

echo imap_fetchbody($con,$index,1);

Um einzelne Dateianhänge auszulesen oder zwischen der Text- und HTML-Version einer Nachricht unterscheiden zu können, finden Sie auf der Heft-CD eine Klasse namens mailbox.class.php. Diese Grundversion ist nicht optimiert, bietet aber bereits die wichtigsten Funktionalitäten, um den Zugriff zu erleichtern und zu verstehen.


Nachrichten versenden

Webmailer mit PHP

Der Versand einer Mail ist indes umständlich. Denn mit der imap-Bibliothek ist dies zwar möglich, jedoch wird dafür der lokale SMTP-Server verwendet. Somit funktioniert dies nur, wenn als Betriebssystem Unix beziehungsweise Linux zum Einsatz kommt. Mit Windows funktioniert der Versand mittels imap_mail jedoch nicht. Und was ist, wenn der SMTP-Dienst auf einem ganz anderen Server läuft als dem, auf dem der Webmailer installiert ist?

Das Erzeugen der Mail bewerkstelligen Sie mit der Funktion imap_compose. Dazu müssen Sie einen Umschlag (envelope) sowie den Nachrichtenbody definieren.

$envelope['from'] = $from;
$envelope['to'] = $to;
$envelope['cc'] = $cc;
$envelope['date'] = date('r');
if($subject != ''))
{
$envelope['subject'] = $subject;
}

Die Definition des Nachrichtenbodys ist genauso einfach:

$message[0]['type'] = TYPETEXT;
$message[0]['subtype'] = 'plain';
$message[0]['description'] = 'message mode text';
$message[0]['contents.data'] = $text."\n\n\n\t";

Achten Sie aber darauf, dass $message ein Array sein muss. Jeder Teil, der einer Nachricht hinzugefügt werden soll, muss dabei als eigenständiges Element im Array definiert sein.

Ist die zu sendende E-Mail-Nachricht als HTML-Mail formatiert, müssen Sie als subtype an dieser Stelle html angegeben, damit die Nachricht ordnungsgemäß versendet wird.

Anschließend können Sie nun mit der Funktion imap_mail_compose den Datenteil der entsprechenden E-Mail-Nachricht erzeugen:

$emaildata = imap_mail_compose($envelope,$message);

Anschließend kann die E-Mail versendet werden. Mit fsockopen wird eine Verbindung zum SMTP-Server aufgebaut.

$sh = fsockopen($host,$port);

SMTP ist genau wie POP3 oder HTTP ein textbasiertes Protokoll. Alle Anweisungen werden im Klartext übertragen. So ist es nicht weiter schwierig, die Mail quasi von Hand zu verschicken.

Mit fputs können Sie Kommandos an den SMTP-Server schicken, der Ihnen ? je nach Erfolg oder Misserfolg ? Antworten im Klartext zurücksendet. Zunächst folgt die Begrüßung des Servers mit dem Kommando HELO und der Domain des Absenders.

fputs($sh,"HELO $domain\r\n");

Die Kommandos selbst müssen durch die Zeichenfolge \r\n (entspricht einem Wagenrücklauf und Zeilenumbruch) abgeschlossen werden. Anschließend werden noch der Absender (MAIL FROM) sowie der Empfänger (RCPT TO) der E-Mail-Nachricht mitgeteilt.

fputs($sh,"MAIL FROM: $from\r\n");
fputs($sh,"RCPT TO: $to\r\n");


Kommunikation mit dem Server

Webmailer mit PHP

Wichtig ist, dass Sie alle Antworten des Servers auslesen, nachdem Sie einen Befehl gesendet haben. Alle Antworten enden mit der Zeichenfolge \n, so dass diese in einer Schleife ausgelesen werden können. Zusätzlich darf dem Server ein wenig Bedenkzeit eingeräumt werden. Da hilft die Funktion usleep.

usleep(125000);
$answer = '';
do
{
$ch = fgetc($sh);
$answer .= $ch;
}
while($ch <> "\n");

Mit dem Kommando DATA teilen Sie dem Server mit, dass die Mail-Daten folgen.

fputs($sh,"DATA\r\n");

Lesen Sie die Antwort aus und schicken Sie anschließend das Ergebnis des Funktionsaufrufs imap_mail_compose.

fputs($sh,"$emaildata\r\n");

Damit der Server weiß, dass keine Mail-Daten mehr folgen, müssen Sie einen Punkt in einer einzelnen Zeile schicken.

fputs($sh,"\r\n.\r\n");

Nun können Sie den Befehl QUIT zum Schließen der Verbindung absetzen. Die Mail wird verschickt und die Verbindung kann mit fclose geschlossen werden.

fputs($sh,"QUIT\r\n");
fclose($sh);

Ein entsprechendes Beispiel finden Sie auf der beiliegenden Heft-CD im Skript send.php. Mit diesem Skript steht Ihnen bereits ein lauffähiger Webmailer zur Verfügung, der als Basis eigener Entwicklungen dienen kann.

Alle Listings zum Workshop finden Sie auf der Heft-CD und unter
listings.internet-pro.de.