sunny: HTML/Text-Mail versenden

Hallo zusammen,

stehe gerade mal wieder vor einem Problem: Ich möchte ein Mail per PHP versenden und zwar soll es je nachdem ob der Client HTML darstellen kann als HTML- oder Plain-Text-Mail angezeigt werden. Es soll also sowohl das HTML wie auch der Text "in einem" versandt werden.

Dazu habe ich zB. folgendes Posting im Archiv gefunden: http://forum.de.selfhtml.org/archiv/2005/2/t101605/#m623945, es müsste also möglich sein, aber leider funktioniert das nicht so ganz bei mir.

Ich mache derzeit Folgendes (Ausschnitt):
$headers = "From: ".$this->from."\r\n";
$headers .= "MIME-Version: 1.0\r\n".
"Content-Type: multipart/alternative;\n\tboundary="---"\r\n";

So wird der header mal grundsätzlich gesetzt (boundary?).

Im Inhalt der Mail wird dann zuerst das Textmail geschrieben, begonnen wird mit:

"Content-Type: text/plain;\r\n\t".
"Content-Transfer-Encoding: 8bit\r\n\r\n".
"Hier steht dann mein Plain Text Inhalt";

und danach wird dann noch der HTML-Teil angehängt:

"Content-type: text/html; charset=iso-8859-1\r\n".
"Content-Transfer-Encoding: 8bit\r\n\r\n".
"Hier steht dann mein HTML Code";

Ist das so überhaupt möglich? Also dass der Content-type dann nicht direkt im header steht sondern eigentlich im Msg-Text? Im verlinkten Posting habe ich das so verstanden, bei mir wird es allerdings ausgegeben im Mail (die Content-type-Angabe) und das HTML-Mail verschwindet komplett. Denke dass das so nicht möglich ist, oder?

Wie macht man das korrekt?
Der Versand passiert dann über mail():

mail($this->to, $this->subject, $this->message, $headers);

Wobei wie gesagt die beiden untersch. Content-types dann erst in der message enthalten sind, das ist wohl zu spät oder? Wie kann ich das besser lösen?

Hoffe das war jetzt nicht zu verwirrend erzählt.

Liebe Grüße
sunny

  1. Es soll also sowohl das HTML wie auch der Text "in einem" versandt werden.

    Ich mache derzeit Folgendes (Ausschnitt):
    $headers = "From: ".$this->from."\r\n";
    $headers .= "MIME-Version: 1.0\r\n".
    "Content-Type: multipart/alternative;\n\tboundary="---"\r\n";

    Die Trenngrenze zwischen den einzelnen Teilen (boundary) sollte schon etwas komplizierter sein als nur drei Striche, zum Beispiel eine schön lange Zufallszahl.

    Im Inhalt der Mail wird dann zuerst das Textmail geschrieben, begonnen wird mit:

    "Content-Type: text/plain;\r\n\t".
    "Content-Transfer-Encoding: 8bit\r\n\r\n".
    "Hier steht dann mein Plain Text Inhalt";

    und danach wird dann noch der HTML-Teil angehängt:

    "Content-type: text/html; charset=iso-8859-1\r\n".
    "Content-Transfer-Encoding: 8bit\r\n\r\n".
    "Hier steht dann mein HTML Code";

    Woher soll der Empfänger wissen, wo ein Teil aufhört und der andere anfängt? Du hast die Trennung vergessen (deine drei Striche).

    Ist das so überhaupt möglich? Also dass der Content-type dann nicht direkt im header steht sondern eigentlich im Msg-Text?

    Das ist der Sinn der Sache. Im Kopf der Mail steht, dass es sich um eine mehrteilige Nachricht handelt (multipart), deren Teile alternativ zueinander verwendet werden können, je nachdem, welchen der Mailer hübscher findet (alternative).
    Worum es sich bei den Einzelteilen handelt, steht logischerweise bei den Einzelteilen.

    Das Einfachste wäre es gewesen, wenn du dir selbst eine HTML-Mail geschickt und ihren Quelltext inspiziert hättest.

    Egal, so sähe es zum Beispiel richtig aus (als Quelltext):

    MIME-Version: 1.0
    Content-Type: multipart/alternative; boundary="--01C57257.5243A214"

    This is a multi-part message in MIME format.

    --01C57257.5243A214
    Content-Type: text/plain; charset="iso-8859-1"

    blabla

    ------_=_NextPart_001_01C57257.5243A214
    Content-Type: text/html; charset="iso-8859-1"

    <html><body>
    blabla
    </body></html>

    1. Dumm gelaufen, so sollte es sein:

      MIME-Version: 1.0
      Content-Type: multipart/alternative; boundary="--01C57257.5243A214"

      This is a multi-part message in MIME format.

      --01C57257.5243A214
      Content-Type: text/plain; charset="iso-8859-1"
      Content-Transfer-Encoding: 8bit

      blabla

      --01C57257.5243A214
      Content-Type: text/html; charset="iso-8859-1"
      Content-Transfer-Encoding: 8bit

      <html><body>
      blabla
      </body></html>

    2. Hallo Kermit!

      Ahh! Vielen Dank für die Erklärung. Ich hatte das mit dem boundary nicht richtig verstanden. Ist natürlich logisch.

      Das Einfachste wäre es gewesen, wenn du dir selbst eine HTML-Mail geschickt und ihren Quelltext inspiziert hättest.

      Das würde ich ja gern, aber bei mir kommt leider kein HTML-Mail an sondern immer nur PlainText. Da hab ich wohl immer noch irgendetwas ganz falsch gemacht. Es ist jetzt so:

      $headers .= "MIME-Version: 1.0\r\n".
      "Content-Type: multipart/alternative;\n\tboundary="---04CC#Aee#0854---"\r\n";

      MailInhalt:

      "---04CC#Aee#0854---".
      "Content-Type: text/plain;\r\n\t".
      "Content-Transfer-Encoding: 8bit\r\n\r\n".
      "Hier steht mein Plain Text".
      "---04CC#Aee#0854---".
      "Content-type: text/html; charset=iso-8859-1\r\n".
      "Content-Transfer-Encoding: 8bit\r\n\r\n".
      "Hier steht mein HTML".
      "---04CC#Aee#0854---";

      Aber ankommen tut dann wieder nur PlainText:

      Content-Type: text/plain;
      Content-Transfer-Encoding: 8bit

      Hier steht mein Plain Text
      ---04CC#Aee#0854---
      Content-type: text/html; charset=iso-8859-1
      Content-Transfer-Encoding: 8bit

      Hier steht mein HTML.

      Und das HTML bricht auch noch irgendwoam Ende einfach ab (letzte Zeichen fehlen), wieso das denn? Gibt es da eine maximale Zeichenanzahl oÄ? Ich glaub ich mach grad irgendeinen total blöden Fehler den ich selber nicht seh ... :-(

      Lg
      sunny

      1. Das würde ich ja gern, aber bei mir kommt leider kein HTML-Mail an sondern immer nur PlainText. Da hab ich wohl immer noch irgendetwas ganz falsch gemacht. Es ist jetzt so:

        $headers .= "MIME-Version: 1.0\r\n".
        "Content-Type: multipart/alternative;\n\tboundary="---04CC#Aee#0854---"\r\n";

        MailInhalt:

        "---04CC#Aee#0854---".
        "Content-Type: text/plain;\r\n\t".

        ---------------------------------^^
        Der Tabulator hat da nichts zu suchen.

        "Content-Transfer-Encoding: 8bit\r\n\r\n".
        "Hier steht mein Plain Text".
        "---04CC#Aee#0854---".
        "Content-type: text/html; charset=iso-8859-1\r\n".
        "Content-Transfer-Encoding: 8bit\r\n\r\n".
        "Hier steht mein HTML".
        "---04CC#Aee#0854---";

        So wie ich diesen PHP-Code interpretiere (ohne Tabulator), kommt folgendes raus:

        ---04CC#Aee#0854---Content-Type: text/plain;
        Content-Transfer-Encoding: 8bit

        Hier steht mein Plain Text---04CC#Aee#0854---Content-type: text/html; charset=iso-8859-1
        Content-Transfer-Encoding: 8bit

        Hier steht mein HTML---04CC#Aee#0854---

        So funktioniert das nicht, der Trenner muss alleine in einer Zeile stehen. Allerdings deckt sich diese Interpretation nicht mit der Ausgabe, wie du sie darstellst.

        Davon abgesehen habe ich einen Fehler gemacht: Die Trennmarkierung wird bei Nutzung durch zwei führende Bindestriche ergänzt. Heißt es "multipart/alternate; boundary=12345", muss es später im Text lauten

        --12345
        Content-Type: text/plain

        bla

        --12345
        Content-Type: text/html

        Der ganze Mechanismus ist in RFC 2046, Kapitel 5.1 beschrieben, dieses solltest du unbedingt lesen (auch wenn's schwer fällt).

        Ich glaub ich mach grad irgendeinen total blöden Fehler den ich selber nicht seh ... :-(

        Falls es nach dem Studium von RFC 2046 immer noch nicht funktioniert,
        zitiere doch bitte mal den kompletten Quelltext der Mail, die bei dir ankommt. Einige Mailer haben dazu im Menü einen Punkt Ansicht > Quelltext (oder ähnlich), bei Outlook/Express musst du die Mail meines Wissens nach erst in einer Datei speichern (exportieren) und dann die Dateiendung von .eml in .txt ändern.

      2. Hi nochmal,

        Hmm, so ganz hat das mit dem boundary wohl nicht hingehauen, hab jetzt gelesen dass davor immer zwei Bindestriche stehen müssen!?

        Habs jetzt so:

        $headers .= "MIME-Version: 1.0\r\n".
        "Content-Type: multipart/alternative;\r\n\t".
        "boundary="04CCAee0854"\r\n\t";

        $mailmessage = "--04CCAee0854\r\n".
        "Content-Type: text/plain; charset=iso-8859-1\r\n".
        "Content-Transfer-Encoding: 8bit\r\n\r\n".
        "...".
        "--04CCAee0854\r\n\t".
        "Content-type: text/html; charset=iso-8859-1\r\n".
        "Content-Transfer-Encoding: 8bit\r\n\r\n".
        "<html><body>".
        "...".
        "</body></html>".
        "--04CCAee0854";

        Jetzt schauts zwar besser aus, aber funktionieren tut es auch nicht richtig :-(

        Jetzt wird nämlich immer das PlainText-Mail angezeigt, egal ob der Client HTML "kann" oder nicht. Was stimmt denn noch immer nicht?

        Lg,
        sunny

        1. Also, es funktioniert jetzt grundsätzlich einmal. Das Leerzeichen vor dem "boundary" hat gefehlt:

          $headers .= "MIME-Version: 1.0\r\n".
              "Content-Type: multipart/alternative;\r\n".
              " boundary="04CCAee0854"\r\n";

          Allerdings hab ich jetzt noch ein Problem.

          Wenn mein HTML-Teil relativ lang wird dann erhalte ich einen Fehler:

          Warning: mail(): Failed to Receive in [PfadzumScript] on line [wo mail() aufgerufen wird].

          Ich dachte zuerst da wäre irgendein Fehler im HTML-String, dem ist aber nicht so. Zudem kommt der Fehler nur manchmal. Weiß jemand woran das liegen könnte?

          Ich werd da jetzt wieder nicht ganz schlau draus, weil es nämlich nicht bei jedem Sende-Vorgang passiert.

          Lg,
          sunny

          1. Warning: mail(): Failed to Receive in [PfadzumScript] on line [wo mail() aufgerufen wird].

            Ich dachte zuerst da wäre irgendein Fehler im HTML-String, dem ist aber nicht so. Zudem kommt der Fehler nur manchmal. Weiß jemand woran das liegen könnte?

            Es lag am Mailserver - er lieferte immer ein linelength-limit exceeded. Habe alle \n durch \r\n ersetzt, jetzt läuft es.

            Lg
            sunny

            1. Jetzt hab ich aber noch ein Problem.

              Und zwar funktioniert jetzt alles super wenn als Client Outlook verwendet wird. Sowohl HTML-Mails als auch PlainText-Mails kommen genau so an wie sie sollten.

              Schicke ich das Mail allerdings an einen WebMail-Client - zB. gmx, dann ist das Mail leer. Nichts drinnen, gar nichts. Woran liegt denn das jetzt wieder?

              Kann das mit dem Content-Transfer-Encoding zusammenhängen oder woran liegts?

              Mein Code sieht jetzt so aus:

              $headers .= "MIME-Version: 1.0\r\n".
              "Content-Type: multipart/alternative;\r\n".
              " boundary="04CCAee0854"\r\n";

              $mailmessage =
              "--04CCAee0854\r\n".
              "Content-Type: text/plain; charset=iso-8859-1\r\n".
              "Content-Transfer-Encoding: 8bit\r\n\r\n".
              "[Mein Text Mail]\r\n".
              "--04CCAee0854\r\n".
              "Content-type: text/html; charset=iso-8859-1\r\n".
              "Content-Transfer-Encoding: 8bit\r\n\r\n".
              "<html><body>\r\n".
              "[Mein HTML Mail]".
              "</body></html>\r\n".
              "--04CCAee0854\r\n";

              Schön langsam wirds echt zum Verzweifeln ...

              sunny

              1. Hallo nochmal,

                also leider funktioniert das Ganze immer noch nicht, jedenfalls nicht bei Webmail-Clients.

                Hab mir nochmal ein kleines Script zum Testen gebaut und mit verschiedenem Encoding etc. herumprobiert, hab allerdings nicht rausfinden können wo der Fehler liegt, vielleicht sieht ihn ja doch noch jemand:

                $headers .= "MIME-Version: 1.0\r\n".
                    "Content-Type: multipart/alternative;\r\n".
                    " boundary="04CCAee0854"\r\n";

                $message = "\n--04CCAee0854\r\n".
                    "Content-Type: text/plain; charset=iso-8859-1\r\n".
                    "Content-Transfer-Encoding: 8bit\r\n\r\n".
                    "Text Message here\r\n".
                    "--04CCAee0854\r\n".
                    "Content-type: text/html; charset=iso-8859-1\r\n".
                    "Content-Transfer-Encoding: 8bit\r\n\r\n".
                    "<html><body>\r\n".
                    "HTML Message here\r\n".
                    "</body></html>\r\n".
                    "--04CCAee0854\r\n";

                mail($to, $subject, $message, $headers);

                Lg
                sunny

                1. Hallo!

                  also leider funktioniert das Ganze immer noch nicht, jedenfalls nicht bei Webmail-Clients.

                  Jetzt gehts! Hab noch ewig lange herumprobiert und dann bemerkt dass am Ende kein boundary mehr sein darf, dann glauben manche Clients wohl dass da noch etwas käme und stellen ein leeres Mail dar!

                  Lg
                  sunny

                  1. Hallo noch einmal,

                    Jetzt gehts! Hab noch ewig lange herumprobiert und dann bemerkt dass am Ende kein boundary mehr sein darf, dann glauben manche Clients wohl dass da noch etwas käme und stellen ein leeres Mail dar!

                    Nachtrag:

                    Also korrekterweise muss am Ende doch ein boundary stehen, allerdings einer der das Ende kennzeichnet ;-)

                    Das hatte ich leider in oben geposteten Link http://www.faqs.org/rfcs/rfc2046.html übersehen:

                    The boundary delimiter line following the last body part is a
                    distinguished delimiter that indicates that no further body parts
                    will follow.  Such a delimiter line is identical to the previous
                    delimiter lines, with the addition of two more hyphens after the
                    boundary parameter value.

                    Lg,
                    sunny