Edgar Ehritt: Mail versenden in HTML und Normal Formatiert

Beitrag lesen

Teil 2:

Damit ein Mailprogramm dort durchsieht, regelt RFC 2045, wie genau die Formatierung zu erfolgen hat. Gucken wir uns am besten mal die letzte Werbung von gmx an. Ich werde zum Oktoberfest verladen - äh, aha:

#####################################################

Return-Path: mailings@gmx-gmbh.de
Date: Fri, 18 Sep 2009 17:17:03 GMT
From: GMX Magazin mailings@gmx-gmbh.de
To: Alle Mitglieder von GMX members@gmx.net
Subject: Einladung zum Oktoberfest!
Message-ID: 20090920004540.28344abod0@mmail04.gmx.net

MIME-Version: 1.0
   Content-Type: multipart/alternative; boundary="gmxboundary=-1253407540-28344-top"

--gmxboundary=-1253407540-28344-top
   Content-Type: text/plain; charset="iso-8859-1"
   Content-Transfer-Encoding: quoted-printable

bla bla bla... (Nichts gegen ein Weizen und den süßen Senf, aber mal ehr-
   lich, die Wurst schmeckt doch wie eingeschlafene Füße und das Gebäck mit
   drei Löchern mir zu Luftig)

--gmxboundary=-1253407540-28344-top
   Content-Type: text/html; charset="iso-8859-1"
   Content-Transfer-Encoding: quoted-printable

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
   w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   <html xmlns=3D"http://www.w3.org/1999/xhtml" xml:lang=3D"de" lang=3D"de">
    <!-- Inhalt -->

--gmxboundary=-1253407540-28344-top--
#####################################################

Ganz kurz abgerissen nochmals was Du da siehst: Return-Path-, From- und To-Header hatten wir oben ja schon kurz erwähnt (RFC 5322; 3.6). Date-Header wird durch Abschnitt 3.6.1 i. V. m. Abschnitt 3.3 bestimmt (der versierte PHPler nutzt dafür date('r') - fertig). Subject wird durch Abschnitt 3.6.5, Message-ID durch Abschnitt 3.6.4 definiert.

Damit sind wir beim eigentlichen Inhalt. Der hat wiederum Header. Diesmal aber zu Formatierung nach MIME. MIME-Version muss immer angegeben werden. Es handelt sich dabei um eine Angabe ähnlich der Prozessoranweisung von XML (<?xml version="x.y"?>). Derzeit gibt es nur die Version 1.0. Nachzulesen ist das dann in der RFC 2045; 4. Content-Type-Header wird seinerseits durch Abschnitt 5 festgelegt. Der Mediatyp ist "multipart/alternative". Diese Angabe legt fest, dass alternative Inhaltsteile zur Anzeige bereitstehen. In der selben Zeile, getrennt vom Semikolon findet man boundary="gmxboundary=-1253407540-28344-top". Das ist der Grenzwert, der die einzelnen Teile, also in Deiner Frage Text und HTML, separiert. Dazu wird jeder Teil mit dem Wert vom Parameter boundary und dem Prefix "--" unterteil. RFC 2045 hat zwar die alter RFC 1521 abgelöst. Leider geht sie auf diesen Punkt weiter nicht mehr ein. Genau beschrieben ist es also in RFC 1521; 7.2.3.

Es ergibt sich also folgende Inhaltsstruktur:

Nachricht in multipart/alternative
   |
   |- Teil in text/plain
   |
   `- Teil in text/html

Ein Mailprogramm nimmt bring daraufhin je nach Konfiguration oder Anzeigemöglichkeit den jeweiligen Teil der Nachricht zur Anzeige. Es ist ebenso möglich, dass man noch andere oder mehrere Mediatypen alternativ anbietet. Man ist zahlenmäßig an keine Obergrenze gebunden. So könnte man neben Text und HTML zusätzlich PDF, XML, Office-Dokumente, ... als Alternativen in einer einzigen Nachricht anbieten.

Die zweite Frage ist die, wie binde ich Bilder, z.B. ein Logo, in die Mail ein, dass die Mail auch offline sauber aussieht?

Neben dem Mediasubtyp "alternative" gibt es noch andere. Um Bilder inline mitzusenden nimmt man den Subtyp "related":

#####################################################

[IMF-Header]

MIME-Version: 1.0
   Content-Type: multipart/related; boundary="gmxboundary=-1253407540-28344-top"

--gmxboundary=-1253407540-28344-top
   Content-Type: text/html; charset="iso-8859-1"
   Content-Transfer-Encoding: quoted-printable

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
   w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   <html xmlns=3D"http://www.w3.org/1999/xhtml" xml:lang=3D"de" lang=3D"de">
    <!-- Inhalt -->
    <img src=3D"cid:image"/>
    <!-- immer noch Inhalt -->

--gmxboundary=-1253407540-28344-tob
   Content-ID: <image1>
   Content-Type: image/gif
   Content-Transfer-Encoding: base64
   Content-Disposition: inline; filename="service145.gif"

R0lGODlhkQAPALMAABxEm+Xl6/7+/vf3+fT09uzs7/39/fHx9Pv7+////9/g5gAAAAAAAAAA
   AAAAAAAAACH5BAAAAAAALAAAAACRAA8AAATaUMlJq7046827/6CWjGRpnmiqrmzrvnCMSklo
   33iu71QSAMCAcEgsGo/IpHLJbDqfUCGtAAQUrtisdsvter/gsHhMLl9ph+phzW673/C4fE6v
   2+/4/JpGqBL+gIGCg4SFhoeIiYqLjI1/NANVA5OUlZaXmJmam5ydnp+goZM0CFUIp6ipqqus
   ra6vsLGys7S1p6Smtrq7vL2+vDQGVQbExcbHyMnKy8zNzs/Q0dLENAJVAtjZ2tvc3d7f4OHi
   4+Tl5tg0CVUy7O3u7/Dv6fH09fb3MTz6+/z9IBEAOw==

--gmxboundary=-1253407540-28344-top--
#####################################################

Auf die einzelnen RFC-Abschnitte gehe ich jetzt nicht mehr weiter ein. Zu beachten ist jetzt die Angabe der Source im <img>-Element "cid:image". Diese korrespondiert mit dem Wert des Content-ID-Headers. Die eigentliche Datei "service145.gif" wird wie oben Text und HTML einfach in der Nachricht abgelegt. Dazu ist sie base64-Kodiert. Das macht die PHP-Funktion base64_encode() freundlicher weise für den Programmierer. Auch hier wieder ergibt sie eine Unterteilte Inhaltsstruktur:

Nachricht in multipart/related
   |
   |- Teil in text/html
   |
   `- Teil in image/gif

Wie zu sehen ist, kann man jeden Mediatypen in einer Nachricht ablegen. Das ist ganz nützlich. Was nutzt einem nämlich entweder Text und HTML oder HTML und Bild zu haben?

#####################################################

[IMF-Header]

MIME-Version: 1.0
   Content-Type: multipart/alternative; boundary="gmxboundary=-1253407540-28344-top"

--gmxboundary=-1253407540-28344-top
   Content-Type: text/plain; charset="iso-8859-1"
   Content-Transfer-Encoding: quoted-printable

bla bla bla... (Nichts gegen ein Weizen und den süßen Senf, aber mal ehr-
   lich, die Wurst schmeckt doch wie eingeschlafene Füße und das Gebäck mit
   drei Löchern mir zu Luftig)

--gmxboundary=-1253407540-28344-top
   Content-Type: multipart/related; boundary="gmxboundary=-1253407540-28344-sub"

--gmxboundary=-1253407540-28344-sub
   Content-Type: text/html; charset="iso-8859-1"
   Content-Transfer-Encoding: quoted-printable

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
   w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   <html xmlns=3D"http://www.w3.org/1999/xhtml" xml:lang=3D"de" lang=3D"de">
    <!-- Inhalt -->
    <img src=3D"cid:image"/>
    <!-- immer noch Inhalt -->

--gmxboundary=-1253407540-28344-tob
   Content-ID: <image1>
   Content-Type: image/gif
   Content-Transfer-Encoding: base64
   Content-Disposition: inline; filename="service145.gif"

R0lGODlhkQAPALMAABxEm+Xl6/7+/vf3+fT09uzs7/39/fHx9Pv7+////9/g5gAAAAAAAAAA
   AAAAAAAAACH5BAAAAAAALAAAAACRAA8AAATaUMlJq7046827/6CWjGRpnmiqrmzrvnCMSklo
   33iu71QSAMCAcEgsGo/IpHLJbDqfUCGtAAQUrtisdsvter/gsHhMLl9ph+phzW673/C4fE6v
   2+/4/JpGqBL+gIGCg4SFhoeIiYqLjI1/NANVA5OUlZaXmJmam5ydnp+goZM0CFUIp6ipqqus
   ra6vsLGys7S1p6Smtrq7vL2+vDQGVQbExcbHyMnKy8zNzs/Q0dLENAJVAtjZ2tvc3d7f4OHi
   4+Tl5tg0CVUy7O3u7/Dv6fH09fb3MTz6+/z9IBEAOw==

--gmxboundary=-1253407540-28344-sub--
   --gmxboundary=-1253407540-28344-top--
#####################################################

Es ergibt sich nunmehr folgende Inhaltsstruktur:

Nachricht in multipart/alternative
   |
   |- Teil in text/plain
   |
   - Teil in multipart/related       |       |- Unterteil in text/html       |       - Unterteil in image/gif

So, jetzt kannst Du Deine Liebesbriefe elektronisch verschicken.

Gruß aus Berlin!
eddi

--
Was haben wir denn heute? "Kampf der Titanen" - Aha! Es treten an 0 und 1.