Das Internet Message Access Protocol ist komplex, vielgestaltig und ungewöhnlich offen für Erweiterungen. Wer die Mechanismen im Ansatz versteht, begreift auch die Geheimnisse und Unterschiede hinter und zwischen den MTAs und IMAP-Mailprogrammen, die Gegenstand dieses Titelthemas sind.
Auch wenn die Beschreibung des IMAP-Standards [1] weit mehr als 100 Seiten umfasst, erklärt sie das Protokoll doch nur zum Teil. Der Autor Marc Crispin schreibt im RFC 3501: “Abgesehen vom Überblick über das Protokoll in Abschnitt 2 ist es nicht optimal auf diejenigen zugeschnitten, die die Handhabung des Protokolls verstehen wollen.”
Ein erstes Beispiel dafür liefern Status-Informationen (Flags), die eine Mail besitzen kann. Der IMAP-Standard schreibt kaum vor, welche es genau gibt; Server und Client dürfen sich darum über zusätzliche Flags und deren Natur verständigen. Und: Flags können permanent (gelesen, wichtig), aber auch sitzungsbasiert sein (neu, gelöscht). Welche Flags es gibt, ist von Ordner zu Ordner unterschiedlich. Außerdem liegt die Flag-Tücke im logischen Detail: Wenn beispielsweise ein Client auf ein Verzeichnis nur lesend zugreifen darf, schafft er es nicht, permanente Flags zu verändern.
Obwohl IMAP alle Informationen auf dem Server speichert, bietet es auch Funktionen, die dem Client erlauben Details lokal zu speichern und über mehrere Logins erneut zu benutzen, zum Beispiel für das lokal vorgehaltene Inhaltsverzeichnis. Das ist nicht trivial, da sich zwischenzeitlich Änderungen am Mailverzeichnis ergeben können. Darum nummeriert IMAP die E-Mails sowohl lückenlos mit linear aufsteigenden Sequenznummern (etwa 1 bis 399) als auch mit so genannten Unique-IDs.
Unveränderliches ändern
Unique IDs sind für jede Mail eindeutig und sollten sich pro Mail nie ändern. Gegenteiliges kann gleichwohl in manchen Konstellationen passieren. Diese Fälle erkennt der Client anhand eines speziellen Unique-ID-Value auf dem Server und liest die Liste der Mails und Unique-IDs neu ein, um sich zu synchronisieren.
Disconnected IMAP, auch Offline IMAP genannt, speichert noch deutlich mehr Informationen auf dem Client und verhilft gewissermaßen IMAP auch noch zu den Vorteilen von POP3. Dabei hält der Mailclient den kompletten Datenbestand des Mail-Postfachs lokal vor. Der Nutzer kann Ordner offline anlegen, Mails verschieben, flaggen oder löschen. Beim nächsten Connect synchronisieren Client und Server alle Änderungen. Die Methode funktioniert nach anfänglichen Macken mittlerweile erstaunlich gut, und zwar – dank IMAPs Flexibilität – ohne ein eigenes Protokoll zu etablieren.
Gern auch unseriell
Funktional und komplex zugleich wird eine IMAP-Sitzung auch dadurch, dass der Client mehrere Kommandos parallel zum Server senden und die Antworten in anderer Reihenfolge erhalten kann. So darf der Client einen komplexen Suchbefehl an den Server senden und ohne auf das Ergebnis zu warten neue Mails hochladen oder Ordner anlegen. Damit der Client die eintreffenden Antworten seinen Anforderungen zuzuordnen weiß, taggt er sie, versieht sie also mit irgendeiner eindeutigen Kennung, die er sich aussuchen darf. Die Antworten des Servers tragen die gleiche Kennung. Schon der Login muss ein Tag benutzen, in diesem Beispiel »a1«:
a1 login User Password
Der Server antwortet daraufhin »a1 OK LOGIN OK«. In der Wahl des Tag ist der Client frei, solange er nie das gleiche Tag parallel mehrmals benutzt. Statt »a1« wie im Beispiel eben, wären »001« oder »abc« gleich gut gewesen.
Dummerweise fallen manche Antworten eines Servers mehrzeilig aus. Man unterscheidet darum zwischen getaggten und ungetaggten Antworten. Letztere beginnen mit einem Sternchen und enden mit einer getaggten Zeile. Das Kommando »NOOP« ist so ein Fall, das manchmal eine mehrzeilige Antwort und damit ungetaggte Antworten provoziert.
Laisser-faire
Eigentlich befördert »NOOP« keine Aktion. Der Client sendet es gewöhnlich, um die Verbindung offen zu halten. Als Reaktion informieren manche Server jedoch über die Anzahl der neuen, gelesenen oder gelöschten E-Mails. Ein solches »a13 NOOP« eignet sich dazu, den Unterschied zwischen getaggten und ungetaggten Antworten zu verdeutlichen:
* 22 EXPUNGE * 23 EXISTS * 3 RECENT * 14 FETCH (FLAGS (Seen Deleted)) a13 OK NOOP completed
Dieses und die nachfolgenden Beispiele kann jeder leicht nachvollziehen, der Zugriff auf einen IMAP-Server hat, egal ob ein eigener, der eines Internetproviders oder ein IMAP-Postfach bei einem der klassischen Mailanbieter. Einzige Voraussetzung ist, dass im Postfach des Accounts bereits einige neue Nachrichten liegen. Eine Verbindung zum IMAP-Port 143 des Servers ist in Listing 1 per Telnet schnell aufgebaut. Ein echter IMAP-Client macht auch nichts anderes.
|
Listing 1: »telnet |
|---|
01 Trying 192.0.2.12... 02 Connected to imap.example.com. 03 Escape character is '^]'. 04 * OK [CAPABILITY IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA IDLE AUTH=CRAM-MD5 AUTH=CRAM-SHA1 ACL ACL2=UNION] Courier-IMAP ready. Copyright 1998-2005 Double Precision, Inc. See COPYING for distribution information. |
Wie flexibel IMAP ist, zeigt die »CAPABILITY«-Vielfalt. Mit ihnen teilt der Server dem Client mit, welche Features er unterstützt. RFC 3501 verlangt von jedem IMAP-Server die Fähigkeit eines Klartext-Logins (»PLAIN«) sowie den Wechsel zu einer SSL/TLS-gesicherten Verbindung mittels »STARTTLS«.
Nach dem vorhin schon beschriebenen Login wechselt die Verbindung in den Authenticated-Status. In Listing 2 verschafft das Kommando »LIST« eine Übersicht über alle Verzeichnisse. Erlaubt ist es auch, gezielt Patterns für die Ordnernamen anzugeben, beispielsweise »a3 LIST “” “INBOX.Priv*”«:
* LIST (HasNoChildren) "." "INBOX.Privates.Urlaub" * LIST (HasNoChildren) "." "INBOX.Privates.Orchester" * LIST (HasChildren) "." "INBOX.Privates" a3 OK LIST completed
Der erste an »LIST« übergebene Parameter ist der Namensraum, auf den sich das Listing beziehen soll, die so genannte Referenz. In den beiden Beispielen hier bleibt sie leer (»””«), da sie sich auf die »INBOX« beziehen. Komplexe Setups dagegen könnten einen Pfad übergeben, auf den sich das Suchpattern relativ bezieht. IMAP sieht übrigens auch öffentliche Ordner vor, leider wissen das nicht alle Clients (siehe Abbildung 2).
|
Push und Pull |
|---|
|
IMAP ist ebenso wie FTP oder SMTP ein sitzungsbasiertes Protokoll, siehe Kasten “IMAP-Verbindungszustände”. Das Gegenteil davon wäre beispielsweise HTTP, bei dem der Client jeden Request einzeln abfeuert und ein Request nicht davon abhängt, was vorher bei dieser Sitzung gelaufen ist. Server und Client halten ihre IMAP-Verbindungen meist permanent offen – gern auch über Stunden. Währenddessen schaut der Client alle paar Minuten nach neuen E-Mails (Pull). Die Effektivität entscheidetDoch auch der Server kann den Client über neue Nachrichten informieren. Die PR- und Websprache nennt dies Push-Verfahren. Einige Verzeichnisse auf Änderungen überwachen und den Client informieren erzeugt weit weniger Last, als wenn der Client alle paar Minuten drei Dutzend IMAP-Folder scannt, um dann doch keine neue Mail vorzufinden. Das per »IDLE«-IMAP-Kommando [2] erzeugte Push ist darum performanter und erstrebenswerter als Pull. |
|
Listing 2: »a2 LIST “” |
|---|
01 * LIST (HasNoChildren) "." "INBOX.Privates.Urlaub" 02 * LIST (HasNoChildren) "." "INBOX.Privates.Orchester" 03 * LIST (HasChildren) "." "INBOX.Privates" 04 * LIST (HasNoChildren) "." "INBOX.ToDo" 05 * LIST (HasNoChildren) "." "INBOX.Test" 06 * LIST (HasChildren) "." "INBOX.Buchzeugs" 07 * LIST (HasNoChildren) "." "INBOX.Buchzeugs.LPIC-1" 08 * LIST (HasNoChildren) "." "INBOX.Buchzeugs.Postfix 3" 09 * LIST (HasNoChildren) "." "INBOX.Buchzeugs.Snort" 10 * LIST (HasNoChildren) "." "INBOX.Buchzeugs.IMAP" 11 * LIST (Unmarked HasChildren) "." "INBOX" 12 a2 OK LIST completed |

Abbildung 2: Nie mehr allein – IMAP kennt von mehreren Accounts gemeinsam nutzbare IMAP-Folder. Gute Mailclients erkennen die unterschiedlichen Namensräume und berücksichtigen dies auch bei der Darstellung.
Ordner müssen zum Benutzen selektiert sein
Nun sollte der Client mit dem »SELECT«-Befehl einen Ordner auswählen, im Beispiel den Ordner »Test« unterhalb der »INBOX«. Auf ihn beziehen sich alle weiteren nachrichtenbezogenen Kommandos – und zwar so lange, bis der Client einen anderen Ordner wählt oder sich mit »LOGOUT« abmeldet. »SELECT« sind, wie den IMAP-Kommandos überhaupt, Vererbungen in der Ordnerhierarchie egal: Wenn ein Befehl etwa »INBOX.Buchzeugs« aus Listing 2 benutzt, bleiben Unterordner wie »INBOX.Buchzeugs.LPIC-1« davon unbeeinflusst.
Die Antwort auf das »SELECT«-Kommando in Listing 3 fällt relativ kompliziert aus. In Zeile 1 berichtet der Server über die im Ordner zulässigen E-Mail-Flags, denn diese sind, wie erläutert, nicht fest vorgegeben. Klassischerweise handelt es sich um:
- »Answered« – als beantwortet markiert
- »Deleted« – zum Löschen vorgemerkt
- »Draft« – als Entwurf markiert
- »Flagged« – als wichtig markiert
- »Recent« – neue Nachricht seit dem letzten
Login - »Seen« – als gelesen markiert
Zeile 2 in Listing 3 listet jene Flags auf, die der Client dauerhaft ändern kann. Liefert der Server diese Zeile nicht, darf der Client davon ausgehen, dass sich alle Flags modifizieren lassen. Das Stichwort »EXISTS« in Zeile 3 verrät, wie viele Nachrichten der Ordner insgesamt enthält – hier drei. Und dass seit dem letzten Login nur eine einzige neue Nachricht eingegangen ist, erfährt der Client aus der »RECENT«-Angabe.
|
Listing 3: »a4 SELECT |
|---|
01 * FLAGS (Draft Answered Flagged Deleted Seen Recent) 02 * OK [PERMANENTFLAGS (Draft Answered Flagged Deleted Seen)] Limited 03 * 3 EXISTS 04 * 1 RECENT 05 * OK [UIDVALIDITY 1175900586] Ok 06 * OK [MYRIGHTS "acdilrsw"] ACL 07 a1 OK [READ-WRITE] Ok |
Zeile 5 gibt den derzeit gültigen Unique-ID-Wert an. Anschließend übermittelt der Server, welche Zugriffsrechte der Client auf das Verzeichnis hat. Die Buchstabenkürzel »acdilrsw« unterscheiden filigran zwischen Spielarten von Lesen, Schreiben und Löschen. Da hier der Client auch der Besitzer des Verzeichnisses ist, verfügt er über alle Rechte. Anders würde es bei einem gemeinsam genutzten Folder aussehen, den einzelne Accounts nur lesen dürfen.
Mit Zeile 7 beendet der Server das »SELECT«-Kommando. Wenn der Client Schreibzugriff auf den Ordner hat, sollte der Server laut IMAP-RFC dem »OK«-Kommando die Information »[READ-WRITE]« hinzufügen. Hat der Client ausschließlich Leserechte, muss er »[READ-ONLY]« melden. Der »SELECT«-Befehl ist übrigens nicht mit dem hier nicht weiter besprochenen »SUBSCRIBE«-Befehl zu verwechseln, mit dem der Client (s)eine Auswahl Ordner auf dem Server abonniert.
|
IMAP-Verbindungszustände |
|---|
|
Eine IMAP-Sitzung lässt sich als Zustandsdiagramm wie in Abbildung 1 beschreiben. Sie pendelt zwischen den Zuständen – eine normale IMAP-Verbindung meist zwischen “Authenticated” und “Selected”. Daraus ergibt sich aber auch, dass nicht zu jedem Zeitpunkt jedes Kommando erlaubt ist. RFC 3501 nennt folgende Hauptzustände: Not Authenticated: Typischerweise der Zustand zwischen dem Connect und der erfolgreichen Authentifizierung. Dementsprechend sind nur wenige Befehle wie »STARTLS«, »LOGIN«, »LOGOUT« und »NOOP« zulässig. Authenticated: Der Client hat sich mit Username und Passwort authentifiziert, aber noch keinen Ordner ausgewählt. Er kann sich über IMAP-Verzeichnisse informieren, neue anlegen, vorhandene abonnieren, abbestellen oder löschen. Das Lesen oder Speichern von E-Mails ist hier nicht möglich – schließlich bleibt unklar, welche E-Mails und Verzeichnisse gemeint sein könnten. Selected: Der Client hat Farbe bekannt und ein einzelnes Verzeichnis mit einem der Befehle »SELECT«, »EXAMINE« oder »STATUS« ausgewählt. Er kann nun Mailkommandos absetzen, die sich auf die Mails dieses Verzeichnisses beziehen. Wählt der Client mittels »CLOSE« oder »EXPUNGE« ein Verzeichnis wieder ab, wechselt die Verbindung zurück in den Status Authenticated. Logout: Der Client gibt mit einem »LOGOUT« kund, dass er sich abmelden will. Jetzt erst löscht der Server alle als »Deleted« markierten Nachrichten, denn auch bei einem unkontrollierten Verbindungsabbruch sollten sie stets erhalten bleiben. Anschließend verabschiedet sich der Server und trennt die Verbindung. |
Fetch-Kommando
Nun kann der Client Nachrichten im Ganzen oder Teile davon abrufen. Für den Aufbau des Inhaltsverzeichnisses beispielsweise reichen die Mailheader. Über das Kommando »FETCH« lässt sich sehr genau steuern, welche Mails und welche ihrer Teile der Server übertragen soll. Listing 4 zeigt in Auszügen ein Beispiel, bei dem ein Mailclient von drei Nachrichten die für das Inhaltsverzeichnis wichtigen Informationen abholt.
|
Listing 4: »a5 FETCH 1:3 |
|---|
01 * 1 FETCH (FLAGS (Seen) INTERNALDATE "07-Apr-2007 01:03:06 +0200" RFC822.SIZE 1647 ENVELOPE ("Sat, 7 Apr 2007 01:01:51 +0200" "Testnachricht 1" (("Peer Heinlein" NIL "p.heinlein" "heinlein-support.de")) (("Peer Heinlein" NIL "p.heinlein" "heinlein-support.de")) (("Peer Heinlein" NIL "p.heinlein" "heinlein-support.de")) (("Peer Heinlein" NIL "p.heinlein" "heinlein-support.de")) NIL NIL NIL "<200704070101.52187.p.heinlein@heinlein-support.de>"))
02 * 2 FETCH (FLAGS () INTERNALDATE "07-Apr-2007 01:03:06 +0200" RFC822.SIZE 1646 ENVELOPE ("Sat, 7 Apr 2007 01:02:01 +0200" "Testnachricht 2" [...]
03 * 3 FETCH (FLAGS () INTERNALDATE "07-Apr-2007 01:03:06 +0200" RFC822.SIZE 1651 ENVELOPE ("Sat, 7 Apr 2007 01:02:10 +0200" "Und Testnachricht 3" [...]
04 a5 OK FETCH completed.
|
Das Schlüsselwort »ALL« in Listing 4 steht nicht für alle Nachrichten, sondern für eine Auswahl relevanter Header-Informationen, aus denen der Client sein Inhaltsverzeichnis erzeugt. Wer die gesamte Nachricht übertragen bekommen will, gibt wie in Listing 5 das Schlüsselwort »BODY[]« an. Auch das Herausgreifen einzelner Headerzeilen ist möglich, zum Beispiel mit »a7 FETCH 2 BODY[HEADER.FIELDS Message-ID]«. Der Server antwortet schmallippig mit
* 2 FETCH (BODY[HEADER.FIELDS("Message-ID")] {59}
Message-Id: <200704070102.01895.p.heinlein@heinlein-support.de>
)
a7 OK FETCH completed.
und gibt nur die Message-ID der zweiten Nachricht preis.
|
Listing 5: »a6 FETCH 2 |
|---|
01 * 2 FETCH (BODY[] {1646}
02 Return-Path: <p.heinlein@heinlein-support.de>
03 X-Original-To: p.heinlein@heinlein-support.de
04 Delivered-To: p.heinlein@heinlein-support.de
05 Received: from [10.0.42.2] (unknown [10.0.42.2])
06 [...]
07 Message-Id: <200704070102.01895.p.heinlein@heinlein-support.de>
08 X-Length: 1519
09 Status: R
10 X-Status: NC
11 X-UID: 0
12
13 Bitte beachten:
14
15 Seit Jahresbeginn gelten wichtige neue Vorschriften
16 f=FCr Signaturangaben von Gesch=E4fts-e-Mails!
17 [...]
18 a6 OK FETCH completed.
|
Kopieren und löschen
Will der Client Nachrichten kopieren oder bewegen, passiert das direkt auf dem Server. Der Client muss die Nachricht also nicht herunter- und wieder hochladen. Beim Befehl »a8 COPY 2:3 INBOX.Privates« ist »INBOX.Privates« das Zielverzeichnis, der noch selektierte Ordner »INBOX.Test« die Quelle. Nach der Aktion antwortet der Server:
a8 OK [COPYUID 1175900586 2:3 25:26] COPY completed.
Die Nachrichten Nummer 2 und 3 finden sich jetzt zusätzlich als Nachrichten 25 und 26 in »INBOX.Privates« wieder. Da ein Move-Kommando nicht existiert, soll »a9 STORE 2,3 +FLAGS Deleted}« als Ausgleich die Nachrichten 2 und 3 in »INBOX.Test« löschen:
* 2 FETCH (FLAGS (Seen Deleted)) * 3 FETCH (FLAGS (Deleted)) a9 OK STORE completed
Der IMAP-Server gibt per »a10 NOOP« für diesen Ordner nun erwartungsgemäß eine andere Statusinformation aus – keine neuen Nachrichten mehr:
* 3 EXISTS * 0 RECENT a10 OK NOOP completed
Die gelöschten Nachrichten verbleiben weiterhin in »INBOX.Test« – sie sind ja nur als »Deleted« markiert und daher vorerst weiterhin benutzbar. Erst wenn der Client den Ordner wieder verlässt, also entweder ein neues Verzeichnis wählt oder ein »UNSELECT« befiehlt, verschwinden die Mails für den Client tatsächlich vom Server.
Suchen lassen
Wer zwischen Client und Server eine sehr dünne Leitung hat, beispielsweise eine GSM-Funkstrecke, weiß die Server-gestützte IMAP-Suche zu schätzen. Anders als POP3, das beim Suchen eines Wortes im Mailbody den kompletten Verzeichnisinhalt übertragen muss, fahndet der IMAP-Server im Auftrag des Clients auf seiner Seite alle E-Mails eines selektierten (!) Verzeichnisses durch und belastet die Leitung nicht. Der Client darf komplexe und mächtige Suchaufträge an den Server vergeben, nach Alter und Größe einer Nachricht, Absender, Headerzeilen, IMAP-Flags und natürlich dem Mail-Inhalt.
Das Ganze ermöglicht Such- und Auswahlfunktionen wie “Alle ungelesenen Mails AND vom Absender xy@bla.de AND Nachrichtennummer > 300”. Eine Suche nach den ungelesenen Mails ist mit »a11 SEARCH ALL UNSEEN« daher keine besondere Herausforderung:
* SEARCH 1 3 a11 OK SEARCH done
Ebenso eine Suche nur in den ersten drei Nachrichten mit »a12 SEARCH 1:3 DELETED«, die die eben zum Löschen markierten Nachrichten wiederfindet:
* SEARCH 2 3 a12 OK SEARCH done
Und wenn der Client den Inhalt mit »a13 SEARCH ALL TEXT Heinlein« durchsucht, antwortet der Server mit:
* SEARCH 1 2 3 a13 OK SEARCH done
Das bedeutet, dass sich ein oder eine »Heinlein« in den ersten drei Nachrichten verewigt hat.
Die Fähigkeiten von IMAP sind wie zu erwarten an dieser Stelle noch lange, lange nicht erschöpft, allein schon deshalb, weil sich RFC 3501 [1] diverse Türen offen hält. So darf jeder IMAP-Server eigene Kommandos ersinnen und deren Fähigkeiten dem Client beim Login als »CAPABILITY« anbieten. Alle erdachten IMAP-Kommandos müssen jedoch mit »X« beginnen und der Server darf dem Client nie abverlangen, dass er X-Kommandos versteht und akzeptiert. Mit diesem Mechanismus kann der Client sich aber auf einzelne IMAP-Server einstellen und deren erweiterte Befehlssätze gezielt ausnutzen.
In Summe bietet das Protokoll Servern wie Clients vielfältige Möglichkeiten, auch komplexe Aufgaben effizient auf den Server auszulagern und Übertragungsvolumen zu sparen. Die Schattenseite: Mailclients wie IMAP-Server implementieren das schwer überschaubare Protokoll in denkbar unterschiedlicher Qualität und Performance.
Das Designkonzept von IMAP hat es also in sich, positiv wie negativ. Etwas Mitleid für die Programmierer von IMAP-fähigen Servern (siehe nächster Artikel) und Mailprogrammen (auch dazu folgen zwei Beiträge) ist darum vielleicht angebracht. Aber neben der Erweiterung der Kampfzone macht die Komplexität IMAP zukunftsfähig und flexibel. (jk)
|
Infos |
|---|
|
[1] Aktuelle IMAP-RFC 3501: [http://www.faqs.org/rfcs/rfc3501.html] [2] RFC 2177, »IDLE«-Kommando: [http://tools.ietf.org/html/rfc2177] |
|
Der Autor |
|---|
|
Peer Heinlein [http://www.heinlein-support.de] ist Mailserver-Spezialist seit 1992, lehrt an der Berliner Linux-Akademie und hat mehrere Bücher zum Thema Mail verfasst. Sein Artikel fußt in Teilen auf seinem demnächst erscheinenden Buch “POP3 und IMAP” [http://www.imap-buch.de]. Im Juli richtet Peer zum dritten Mal für Postmaster eine Mailserver-Konferenz aus. |





