Spaces. Smartes Cloud Hosting für anspruchsvolle Webprojekte. Loslegen und Spaces testen. Von Mittwald.
Daniel Dubsky 21. August 2007

Aufbau von MIME-Mails

Kein Beitragsbild

Wer via Skript nicht nur rei­ne Textmails ver­sen­det, son­dern auch HTML-Formatierungen ein­set­zen und Dateianhänge ver­schi­cken will, muss einen ganz bestimm­ten Aufbau beach­ten, damit die Nachrichten in allen Mail-Clients kor­rekt dar­ge­stellt wer­den.

Lese-Tipp: Cerberus: Responsive HTML E-Mail, die über­all funk­tio­niert

Eine Textmail ist leicht ver­schickt, im Prinzip wer­den ledig­lich die Mail-Adresse des Empfängers, ein Betreff und der Nachrichtentext benö­tigt. Diese wer­den dann bei­spiels­wei­se in PHP der Funktion mail() als Argumente über­ge­ben. Schwieriger wird es aller­dings, wenn die Mail Sonderzeichen ent­hält, gar mit HTML for­ma­tiert ist oder ein Dateianhang mit­ge­schickt wer­den soll. Hier müs­sen bestimm­te Konventionen ein­ge­hal­ten wer­den, damit der Empfänger mit die­sem Datenbrocken über­haupt etwas anfan­gen kann. Wenn Sie nicht auf fer­ti­ge Klassen oder Anwendungen zurück­grei­fen, müs­sen Sie die Mail von Hand zusam­men­bau­en.

Eine Mail besteht aus drei Teilen, dem

  • Envelope. Er ent­hält wich­ti­ge Daten wie den Absender und den Empfänger, die der Mail Transfer Agent (MTA) für den Transport und die Zustellung der Mail benö­tigt.
  • Header. Er ent­hält eine Vielzahl von Angaben, die aller­dings nicht für die Zustellung der Mail genutzt wer­den. Die Daten kön­nen daher von denen im Envelope abwei­chen. Der Mail-Client zeigt nor­ma­ler­wei­se nicht alle Header-Daten an, son­dern nur Absender, Empfänger, Betreff und Datum.
  • Body. Dies ist der eigent­li­che Inhalt der Mail, also der Nachrichtentext inklu­si­ve aller Formatierungen und Dateianhänge.

Wie Header und Body auf­ge­baut wer­den müs­sen, ist in den Multipurpose Internet Mail Extensions, kurz MIME, fest­ge­legt. Diese lie­fern dem Empfänger auch Informationen dar­über, wel­che Daten geschickt wur­den und wie sie kodiert sind.

Die Definition des Content-Types
Damit der Mail-Client des Empfängers weiß, dass es sich bei der Mail um eine MIME-Mail und nicht etwa nur einen ein­fa­chen ASCII-Text han­delt, muss im Header der Mail dar­auf hin­ge­wie­sen wer­den. Der Header könn­te dann bei­spiels­wei­se so aus­se­hen:

From: absender@absenderdomain.de
To: empfaenger@empfaengerdomain.de
Subject: blabla
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="=_abgrenzung"

Der Content-Type multipart/alternative zeigt an, dass die nach­fol­gen­den Blöcke im Body der Mail die glei­chen Informationen beinhal­ten, aber unter­schied­li­che Formate haben. Üblicherweise han­delt es sich um die HTML-Version der Mail und eine Textversion für Mail-Clients, die kein HTML anzei­gen kön­nen oder dür­fen. Es gibt auch noch ande­re Content-Typen – je nach­dem wel­cher Art die nach­fol­gen­den Daten sind. Eine Übersicht über die mehr als 100 Content-Typen fin­det sich auf den Webseiten der IANA. Hier die wich­tigs­ten:

  • application/msexcel für Excel-Dateien
  • application/msword für Word-Dateien
  • application/pdf für PDF-Dateien
  • application/zip für ZIP-Dateien
  • image/gif für Bilder im Format GIF
  • image/jpeg für Bilder im Format JPEG
  • image/png für Bilder im Format PNG
  • multipart/alternative für gleich­wer­ti­ge Daten, von denen nur ein Teil ange­zeigt wird (ent­we­der die Text- oder die HTML-Version einer Mail)
  • multipart/mixed für gleich­wer­ti­ge Daten, die zusam­men ange­zeigt wer­den (etwa eine Mail mit meh­re­ren Anhängen)
  • multipart/related für Daten, die zusam­men gehö­ren (etwa eine HTML-Mail mit ein­ge­bun­de­nem Bild)
  • text/html für HTML-Dateien oder HTML-for­ma­tier­te Mails
  • text/plain für Textdateien oder Mails mit Plain Text
  • text/richtext für Richtext-Dateien

Die ein­zel­nen Teile einer MIME-Mail wer­den durch die als bounda­ry defi­nier­te Zeichenkette von­ein­an­der getrennt und ent­hal­ten ihrer­seits noch ein­mal eine Art Sub-Header, der wie der übri­ge Mail-Inhalt ein­fach in den Body geschrie­ben wird. In die­sem Sub-Header wird dann für den fol­gen­den Teil erneut ein Content-Typ ange­ge­ben und – da der Teil der Mail eben­falls aus meh­re­ren Teilen bestehen kann – gege­be­nen­falls auch eine wei­te­re Boundary.

Die Boundary kann frei defi­niert wer­den, man soll­te aller­dings dar­auf ach­ten, dass die Zeichenkette nir­gend­wo sonst in einer Mail vor­kom­men kann. Jeder Teil der Mail beginnt mit der Boundary, der zwei Striche (–) vor­an­ge­stellt wer­den. Nach dem letz­ten Teil folgt erneut eine Boundary, eben­falls mit den zwei Strichen zu Beginn, aber auch mit zwei abschlie­ßen­den Strichen, um dem Mail-Client zu zei­gen, dass kein wei­te­rer Teil mehr folgt. Ein Beispiel:

// Mail-Header
From: absender@absenderdomain.de
To: empfaenger@empfaengerdomain.de
Subject: blabla
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="=_abgrenzung"

// Mail-Body
// Textteil der Mail
–=_abgrenzung
Content-Type: text/plain; charset=iso-8859–1
Content-Transfer-Encoding: quo­ted-prin­ta­ble

Hier der eigent­li­che Text der Mail.

// HTML-Teil der Mail
–=_abgrenzung
Content-Type: text/html; charset=iso-8859–1
Content-Transfer-Encoding: base64

Hier der HTML-Quelltext der Mail.

–=_abgrenzung–

Die Kodierung der Mail
Zwei Dinge fal­len am oben ste­hen­den Beispiel auf. Zum einen muss bei Textmails nach der Angabe des Content-Typs noch der Zeichensatz fest­ge­legt wer­den. Hier kommt übli­cher­wei­se ISO-8859–1 zum Einsatz, der neben den ASCII-Zeichen auch die meis­ten west­eu­ro­päi­schen Sonderzeichen umfasst. Zum ande­ren muss für alle Teile der Mail mit Content-Transfer-Encoding ange­ge­ben wer­den, wie die Daten kodiert sind.

Eine Mail darf näm­lich nur als den 7-Bit-ASCII-Zeichen bestehen. Kommen ande­re Zeichen vor, müs­sen die­se kodiert wer­den – andern­falls kommt beim Empfänger nur Zeichensalat an. Die ein­fachs­te Möglichkeit ist quo­ted-prin­ta­ble; hier wer­den die pro­ble­ma­ti­schen Zeichen ein­fach durch ein Gleichheitszeichen und ihren ASCII-Wert ersetzt, etwa =FC für ü. Da damit aller­dings nicht alle mög­li­chen Zeichen abge­deckt wer­den, nimmt man quo­ted-prin­ta­ble ledig­lich für Textmails. Andere Daten, ins­be­son­de­re Dateianhänge, wer­den meist mit base64 kodiert; in PHP gibt es dafür die Funktion base64_encode().

Die kodier­ten Zeilen von MIME-Mails dür­fen zudem nicht län­ger als 76 Zeichen sein. Sie müs­sen also alle 76 Zeichen einen Zeilenumbruch ein­fü­gen, was in PHP die Funktion chunck_split() über­nimmt.

Dateianhänge und HTML-Mails mit Bildern
Ein Bild an eine Mail anzu­hän­gen, ist nun auch kein Problem mehr. Der Sub-Header für die­sen Teil der Mail sähe zum Beispiel so aus:

Content-Type: image/gif; name="bild.gif"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="bild.gif"

Die Content-Disposition kann auch inli­ne sein, dann wird das Bild nicht als Anhang, son­dern inner­halb der Mail ange­zeigt. Soll es inner­halb des HTML-Teils ein­ge­baut wer­den, wird ihm eine Content-ID zuge­wie­sen: Content-ID: bild1. Über die­se kann das Bild dann mit <img src=“cid: bild1”> ein­ge­bun­den wer­den, der eigent­li­che Name des Bildes ist in die­sem Fall unwich­tig. Der Aufbau einer MIME-Mail mit Textteil und HTML-Teil, der ein Bild ent­hält, das nicht aus dem Web nach­ge­la­den, son­dern als Dateianhang mit­ge­lie­fert wird, sähe so aus:

// Mail-Header
From: absender@absenderdomain.de
To: empfaenger@empfaengerdomain.de
Subject: blabla
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="=_abgrenzung1"

// Mail-Body
// Textteil der Mail
–=_abgrenzung1
Content-Type: text/plain; charset=iso-8859–1
Content-Transfer-Encoding: quo­ted-prin­ta­ble

// Hier der kodier­te Text der Mail.

// HTML-Teil der Mail
–=_abgrenzung1
Content-Type: multipart/related; boundary=“=_abgrenzung2”

// der eigent­li­che HTML-Teil
–=_abgrenzung2
Content-Type: text/html; charset=iso-8859–1
Content-Transfer-Encoding: base64

// Hier der kodier­te HTML-Quelltext der Mail.

// ein Bild, das in den HTML-Teil ein­ge­bet­tet wird
–=_abgrenzung2
Content-Type: image/gif; name=“bild.gif”
Content-Transfer-Encoding: base64
Content-ID: bild
Content-Disposition: inli­ne; filename=“bild.gif”

// Hier das base64-kodier­te Bild.

–=_abgrenzung2–
–=_abgrenzung1–

Um dann etwa mit PHP eine MIME-Mail zu ver­schi­cken, wer­den Header, Boundaries, Sub-Header und die kodier­ten Mail-Inhalte in einen String geschrie­ben – Zeilenumbrüche nicht ver­ges­sen! – und die­ser der Funktion mail() über­ge­ben. (tm)

Daniel Dubsky

Freier Journalist für Computer-und Internet-Themen. Schrieb unter anderem für verschiedene gedruckte Fachzeitschriften.

6 Kommentare

  1. “… zwei Striche (–) vor­an­ge­stellt …” wird vom CMS in einen Gedankenstrich ver­wan­delt. Ansonsten herz­li­chen Dank für die immer wie­der hilf­rei­chen Artikel zum fixen Nachlesen :)

  2. Einfach nur *DANKE* liebe|r Dr.Web! :)
    … Du hast mit die­ser Seite und der eine drei­stün­di­ge ver­zwei­fel­te Suche und rum­pro­bie­ren been­det.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.