Kalle_B: Absenderangabe bei Mails erzwingen

Hallöle,

ich habe ein Serverhousing mit der Hauptdomain xxx.de

Eine eigenständige Domain auf diesem Server ist yyy.de

Wenn ein Besucher nun unter yyy.de ein Mailformular abschickt, wird als Absender 'noreply@xxx.de' angegeben. Ich möchte jedoch yyy.de haben. Hier mein Code:
[code:php]
  //-------------
  // MAIL SENDEN
  //-------------
  $header =
"From: noreply@yyy.de
Content-Type: text/plain; charset="utf-8"";

$subject = "Veranstaltungskalender yyy.de";

$txt = "
".utf8_decode($arr['email_a'])." schickt Ihnen diesen Gruß von der Seite http://yyy.de:

".utf8_decode($arr['nachricht'])."

Auch Sie können den Veranstaltungskalender in Ihre Homepage einbinden oder sich als Veranstalter registrieren bei http://yyy.de
";
  $txt = utf8_encode($txt);

$mail_verschickt = mail( $arr['email_e'],  $subject, $txt, $header );
  if ( $mail_verschickt )
  {
    $mail_verschickt = mail( $arr['email_a'],  "Kopie Ihrer Nachricht: ".$subject, $txt, $header );
  }
}
[/code]
MfG Kalle

  1. Hi Kalle,

    $header =
    "From: noreply@yyy.de
    Content-Type: text/plain; charset="utf-8"";

    ich weiß nicht, ob es eine so gute Idee ist, die Darstellung des Zeilenumbruchs dem Server zu überlassen: Die meisten Server sind Unix-basiert und verwenden ein einfaches Linefeed (0x0A) als Zeilenumbruch; RFC2822 verlangt aber CR/LF (0x0D, 0x0A) als Zeilenumbruch.

    Davon abgesehen sind die Anführungszeichen um "utf-8" hier überflüssig; ich bin mir nicht sicher, ob sie nicht sogar falsch sind.

    $mail_verschickt = mail( $arr['email_e'],  $subject, $txt, $header );
      if ( $mail_verschickt )

    Warum führst du hier noch eine zusätzliche Variable ein? Ein einfaches

    if (mail(...))
      { // weitere Anweisungen
      }

    würde genügen.

    So long,
     Martin

    --
    Wer im Glashaus sitzt, sollte Spaß am Fensterputzen haben.
    1. Hi Martin,

      $mail_verschickt = mail( $arr['email_e'],  $subject, $txt, $header );
        if ( $mail_verschickt )

      Warum führst du hier noch eine zusätzliche Variable ein? Ein einfaches

      if (mail(...))
        { // weitere Anweisungen
        }

      würde genügen.

      Ich brauche die Angabe später zur Anzeige, ob die Mail abgeschickt wurde.

      MfG Kalle

    2. Hello,

      ich weiß nicht, ob es eine so gute Idee ist, die Darstellung des Zeilenumbruchs dem Server zu überlassen: Die meisten Server sind Unix-basiert und verwenden ein einfaches Linefeed (0x0A) als Zeilenumbruch; RFC2822 verlangt aber CR/LF (0x0D, 0x0A) als Zeilenumbruch.

      Das ist nur die halbe Wahrheit und führ tdaher zu Fehlern.

      Die Funktion Mail() kann nur als Helferlein für den Programmierer angesehen werden.
      Es kommt auf die Art und Weise an, wie mail() die email zum MTA transportiert.
      Auf Unix-Hosts wird hierfür meistens ein sendmail-Script verwendet. Dieses ersetzt dann das Executable sendmail. Ob dann hinten dran qmail, exim, postfix oder sonstwer die Arbeit macht, ist egal.

      Wesentlich ist, dass das Script JEDES der beiden Zeilenschaltungszeichen in CRLF verwandelt. Wenn also  nun bereits ein CRLF geliefert wird, dann wird daraus ein CRLFCRLF, was offensichtlich dem MTA nicht behagen wird.

      Ergo: für mail(), wenn die Weiterverarebitung auf einem Unix-Host mittels sendmail geschieht (in der INI ist es ja eingetragen), dann nur LF verwenden für die Separierung der Header.

      Wenn jedoch Windows als OS verwendung findet, dann wird meistens der MTA direkt über Port 25 gefüttert. Dann MUSS man CRLF verwenden, um die Header zu trennen.

      Soweit jedenfalls meine Kenntnisse zu diesem Problem.

      Liebe Grüße

      Tom vom Berg

      --
      Nur selber lernen macht schlau
      1. Hallo Tom,

        ich weiß nicht, ob es eine so gute Idee ist, die Darstellung des Zeilenumbruchs dem Server zu überlassen: Die meisten Server sind Unix-basiert und verwenden ein einfaches Linefeed (0x0A) als Zeilenumbruch; RFC2822 verlangt aber CR/LF (0x0D, 0x0A) als Zeilenumbruch.

        Das ist nur die halbe Wahrheit und führ tdaher zu Fehlern.

        sagen wir's mal so: Die Darstellung war wohl nicht ganz vollständig, okay.

        Die Funktion Mail() kann nur als Helferlein für den Programmierer angesehen werden.
        Es kommt auf die Art und Weise an, wie mail() die email zum MTA transportiert.

        Richtig.

        Auf Unix-Hosts wird hierfür meistens ein sendmail-Script verwendet. [...] Wesentlich ist, dass das Script JEDES der beiden Zeilenschaltungszeichen in CRLF verwandelt. Wenn also  nun bereits ein CRLF geliefert wird, dann wird daraus ein CRLFCRLF, was offensichtlich dem MTA nicht behagen wird.

        Dann ist die Implementierung defekt und gehört gegen etwas Ordentliches ausgetauscht. Ehrlich, diesen "Fehler" habe ich noch nirgends gesehen.

        Tatsache ist wohl, dass viele sendmail-Implementierungen (und wohl auch manche MTAs) fehlerhafte Zeilenschaltungen korrigieren, indem sie _einzeln_ vorkommende LF oder CR in das vorgeschriebene CR/LF-Pärchen umwandeln. Enthält der angelieferte Code aber bereits CR/LF als Kombination, bleibt das normalerweise unangetastet.

        Problematisch kann höchstens im Einzelfall sein, wenn "verkehrte" Zeilenumbrüche in der Form LF/CR übergeben werden. Das wird nicht immer korr^Wwie vom Autor erwartet erkannt und kann daher die CR/LF-Verdopplung auslösen, die du oben beschrieben hast.

        Ergo: für mail(), wenn die Weiterverarebitung auf einem Unix-Host mittels sendmail geschieht (in der INI ist es ja eingetragen), dann nur LF verwenden für die Separierung der Header.

        Ergo: Dem sendmail-Handler oder MTA korrekte Zeilenumbrüche (CR/LF) anzuliefern, ist in nahezu 100% der Fälle richtig; lediglich ein paar wenige, defekte Implementierungen verhunzen diese Zeilenschaltungen.
        Die Mailheader (auch Sub-Header im Multipart-Mails) dagegen nur mit LF zu trennen, ist ein Glücksspiel, das oft funktioniert, aber nicht zuverlässig.

        Wenn jedoch Windows als OS verwendung findet, dann wird meistens der MTA direkt über Port 25 gefüttert. Dann MUSS man CRLF verwenden, um die Header zu trennen.

        Oder darauf hoffen, dass auch der MTA unvollständige Zeilenumbrüche erkennt und akzeptiert, ggf. sogar korrigiert.

        Soweit jedenfalls meine Kenntnisse zu diesem Problem.

        Wenn wir uns zusammentun, kommen wir der Wahrheit vermutlich sehr nahe. ;-)

        Schönes Wochenende noch,
         Martin

        --
        Dieser Satz wurde in mühsamer Kleinstarbeit aus einzelnen Wörtern zusammengesetzt.
          (Hopsel)
        1. Hello,

          Wenn wir uns zusammentun, kommen wir der Wahrheit vermutlich sehr nahe. ;-)

          Das sollten wir unbedingt auch nochmal tun.
          Nur habe ich momentan leider nicht die Möglichkeiten, alles zu untersuchen und auszuprobieren.
          Anfangen könnte man ja mal mit dem PHP-Source-Code von mail().

          Einsteigen müsste wir da wohl Zeile 354 in /main/main.c

          #if defined(PHP_PROG_SENDMAIL) && !defined(NETWARE)

          define DEFAULT_SENDMAIL_PATH PHP_PROG_SENDMAIL " -t -i "

          #elif defined(PHP_WIN32)

          define DEFAULT_SENDMAIL_PATH NULL

          #else

          define DEFAULT_SENDMAIL_PATH "/usr/sbin/sendmail -t -i"

          #endif

          Hier wird bereits zwischen Windows, Unix und Netware unterschieden

          /ext/standard/php_mail.h:
          -------------------------
          #ifndef PHP_MAIL_H
          #define PHP_MAIL_H

          PHP_FUNCTION(mail);
          PHP_MINFO_FUNCTION(mail);

          PHP_FUNCTION(ezmlm_hash);
          PHPAPI extern int php_mail(char *to, char *subject, char *message, char *headers, char *extra_cmd TSRMLS_DC);

          #endif /* PHP_MAIL_H */

          /ext/standard/mail.c
          -------------------------

          239 ff:

          if (sendmail) {
          #ifndef PHP_WIN32
            if (EACCES == errno) {
             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Permission denied: unable to execute shell to run mail delivery binary '%s'", sendmail_path);
             pclose(sendmail);
             return 0;
            }
          #endif
            fprintf(sendmail, "To: %s\n", to);
            fprintf(sendmail, "Subject: %s\n", subject);
            if (headers != NULL) {
             fprintf(sendmail, "%s\n", headers);
            }
            fprintf(sendmail, "\n%s\n", message);
            ret = pclose(sendmail);

          Das sollte Dir zu denken geben.
          So hatte ich es auch in Erinnerung.
          Die Standardheader To:, Subject: und die Zusatzheader als Paket werden alle nur mit "\n" an Sendmail übergeben.

          Ich hatte dazu auch einen Dialog per email mit einem PHP-Programmierer, den ich leider zur Zeit nicht raussuchen kann. Ich befürchte, ich habe ihn nur im eMail-Programm abgelegt und nicht separat auf der Platte gespeichert.

          Die Aussage war (auf Englisch und aus der Erinnerung wiedergegeben):
          da sendmail und alle seine Derivate von einer Konsoleneingabe unter Linux/Unix ausgehen müssen, und diese ja nur "\n" produziert, werden die "\n" intern zu "\r\n" vervollständigt. Dabei gehen alle bekannte Scripte so vor, dass JEDES Zeichen einzeln aufgefüllt wird, also sowohl ein "\r" als auch ein "\n" zu "\r\n" wird. Es wird NICHT darauf geachtet, ob die beiden bereits im Pärchen "\r\n" oder "\n\r" (das wäre sowieso falsch herum) auftreten.

          Die mail-Funktion in PHP wurde deshalb für die Übergabe an sendmail so programmiert.
          Man darf dann also KEINESFALLS zur Begrenzung der (selbst definierten) Header "\r\n" benutzen!

          Für die Ausgabe an Windows (oder Netware) werden alle Parameter nur 1:1 durchgereicht.

          Liebe Grüße

          Tom vom Berg

          --
          Nur selber lernen macht schlau
        2. echo $begrüßung;

          Wenn wir uns zusammentun, kommen wir der Wahrheit vermutlich sehr nahe. ;-)

          Vor gar nicht allzu langer Zeit hatten wir das Thema der Zeilenumbruchszeichen in Mails bzw. bei der Verwendung der PHP-Funktion mail().

          Siehe:
          </archiv/2007/11/t162056/#m1054257>
          </archiv/2007/12/t163212/#m1062802>
          und vor allem
          </archiv/2007/12/t163645/#m1065925>
          sowie die jeweils vorangegangenen Postings.

          Meine Meinung: Mir als Anwender sollte es egal sein können, welche Regeln beim Transport der Mail oder auch jedes beliebigen anderen Dokuments vorgeschrieben sind. Ich sollte die auf meinem System üblichen Zeichen verwenden können. Für die richtige Transportverpackung und damit für eine Umkodierung hat der transportierende Teil zu sorgen. In dem Fall wäre es also mail()s Aufgabe, unter Unix, dem sendmail(-Ersatz) Unix-Zeilenumbrüche zu liefern und unter Windows dem MTA RFC-konforme Umbrüche.

          Soweit zur Theorie. Die konkrete Implementation von mail() spricht eher dafür, dass ich mir doch Gedanken machen muss, welches System mir zugrunde liegt um daraufhin entsprechend selbst tätig zu werden. Es sind ja auch noch einige andere Unterschiede zwischen den Systemen zu beachten, wie die "Note"-Abschnitte der Handbuchseite zu mail() zu berichten wissen (beispielsweise der to-Parameter; unter Windows mag mail() die Form "name addr@example.com" nicht besonders).

          echo "$verabschiedung $name";

          1. Hello deldfix,

            bei der Gelegenheit nochmal nachgefragt:

            http://cvs.php.net/viewvc.cgi/php-src/ext/standard/mail.c?annotate=1.96

            was haben diese merkwürdigen Backslashes in den Zeilen 47ff zu sagen?

            Liebe Grüße

            Tom vom Berg

            --
            Nur selber lernen macht schlau
            1. Hello deldfix,

              bei der Gelegenheit nochmal nachgefragt:

              http://cvs.php.net/viewvc.cgi/php-src/ext/standard/mail.c?annotate=1.96

              was haben diese merkwürdigen Backslashes in den Zeilen 47ff zu sagen?

              Zu der Aussage, die ich bekommen habe, passt auch der Ausschnitt aus dem von Dir zitierten Bugreport:

              http://bugs.php.net/bug.php?id=15841

              <cite>
              Use of CRLF is known to break qmail systems where no conversion of line
              breaks occurs on the input data. In this case using CRLF causes all but
              the first extra header to appear in the message body (CRLF is
              interpreted as two line breaks).
              </cite>

              Liebe Grüße

              Tom vom Berg

              --
              Nur selber lernen macht schlau
            2. echo $begrüßung;

              http://cvs.php.net/viewvc.cgi/php-src/ext/standard/mail.c?annotate=1.96
              was haben diese merkwürdigen Backslashes in den Zeilen 47ff zu sagen?

              Das ist keine echte Funktion sondern eine Macro-Definition. Ich kenne mich mit C kaum aus, meine Interpretation ist, dass Makros nicht länger als eine Zeile sein können und die Backslashes die jeweils nachfolgende Zeile als zum Makro zugehörig kennzeichnen.

              echo "$verabschiedung $name";