Passwort: brauche PHP-Hilfe :-)

Hallo

Nachdem das grosse php-Forum php.de geschlossen ist, bin ich auf der Suche nach einem neuen Forum, wo man mir kompetent bei PHP-Fragen helfen kann.

Es geht bei mir um die Thematik, dass mein Mailprovider in einem Monat auf envelope-from umstellt. Bei meinen Formularen habe ich die Mailadresse der mich kontaktierenden Person als "from" gesetzt, damit ich dann mit meinem Mailprogramm einfach auf Antworten klicken kann. Dies wird künftig nicht mehr gehen. Eine Idee von mir wäre, die Absender-Mailadresse in ein Reply-To zu packen, die Frage ist nur, wie ;-) Ich habe die Seite nicht selbst gecoded sondern jemand, dessen Tagesgeschäft das ist. Er hat für den Mailversand (SMTP) "MailHelper" verwendet. Das Tool hat nach meiner laienhaften Erkenntnis keine Reply-To Option.

Code:

declare(strict_types=1);
	use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;

	class MailHelper
{
	    private PHPMailer $mail;
    private string $ErrorInfo;
	    public function getErrorInfo(): string
    {
        return $this->ErrorInfo;
    }
	    public function hasErrorInfo(): bool
    {
        return !empty($this->ErrorInfo);
    }
	    public function __construct()
    {
        $this->mail = new PHPMailer(true);
        $this->mail->CharSet = PHPMailer::CHARSET_UTF8;
        $this->mail->isHTML(false);
    }
	    /**
     * @throws Exception
     */
    public function toUser(string  $subject,
                           string  $body,
                           string  $to_address,
                           string  $to_name,
                           ?string $from_address = null,
                           ?string $from_name = null): PHPMailer
    {
        if (!$from_address) {
            $from_address = MAIL_FROM_ADDRESS;
        }
	        if (!$from_name) {
            $from_name = MAIL_FROM_NAME;
        }
	        // Validate to address
        if (!filter_var($to_address, FILTER_VALIDATE_EMAIL)) {
            throw new Exception('Invalid to address "'.$to_address.'" for user');
        }
	        // Validate from address
        if (!filter_var($from_address, FILTER_VALIDATE_EMAIL)) {
            throw new Exception('Invalid from address "'.$from_address.'" for user');
        }
	        return $this->handleMail(
            subject: $subject,
            body: $body,
            to_address: $to_address,
            to_name: $to_name,
            from_address: $from_address,
            from_name: $from_name
        );
    }
	    /**
     * @throws Exception
     */
    public function handleMail(string $subject,
                               string $body,
                               string $to_address,
                               string $to_name,
                               string $from_address,
                               string $from_name): PHPMailer
    {
        try {
            /** For SMTP, change the following */
            if (USE_SMTP) {
                $this->mail->isSMTP();
                if (DEBUG) {
                    $this->mail->SMTPDebug = SMTP::DEBUG_SERVER;
                }
                $this->mail->Host = SMTP_HOST;
                $this->mail->SMTPAuth = true;
                $this->mail->Username = SMTP_USERNAME;
                $this->mail->Password = SMTP_PASSWORD;
                $this->mail->SMTPSecure = SMTP_ENCRYPTION;
                $this->mail->Port = SMTP_PORT;
            } else {
                $this->mail->isMail();
            }
	            /** Add the BCC in case there are some given */
            if (count(BCC_RECIPIENTS) > 0) {
                foreach (BCC_RECIPIENTS as $bcc) {
                    // Validate BCC address
                    if (filter_var($bcc, FILTER_VALIDATE_EMAIL)) {
                        $this->mail->addBCC($bcc);
                    }
                }
            }
	            $this->mail->setFrom($from_address, $from_name);
            $this->mail->addAddress($to_address, $to_name);
	            $this->mail->Subject = $subject;
            $this->mail->Body = $body;
	            return $this->mail;
        } catch (Exception $e) {
            $this->ErrorInfo = $e->getMessage();
        }
    }
	    /**
     * @throws Exception
     */
    public function toAdmin(string  $subject,
                            string  $body,
                            ?string $from_address = null,
                            ?string $from_name = null): PHPMailer
    {
        if (!$from_address) {
            $from_address = MAIL_FROM_ADDRESS;
        }
	        if (!$from_name) {
            $from_name = MAIL_FROM_NAME;
        }
	        // Validate to address
        if (!filter_var(MAIL_TO_ADDRESS, FILTER_VALIDATE_EMAIL)) {
            throw new Exception('Invalid to address "'.MAIL_TO_ADDRESS.'" for admin');
        }
	        // Validate from address
        if (!filter_var($from_address, FILTER_VALIDATE_EMAIL)) {
            throw new Exception('Invalid from address "'.$from_address.'" for admin');
        }
	        return $this->handleMail(
            subject: $subject,
            body: $body,
            to_address: MAIL_TO_ADDRESS,
            to_name: MAIL_TO_ADDRESS_NAME,
            from_address: $from_address,
            from_name: $from_name
        );
    }
}

und

$mail = new MailHelper();
	                  $mail->toAdmin(
                    subject: '*subject*',
                    body: $body,      
                    from_address: $inputs['email'],  
                    from_name: $inputs['name']       
                )->send();

Kann mir hier geholfen werden? :-)

Danke & Gruss

  1. Liebe(r) Passwort,

    Deine MailHelper-Klasse verwendet den PHPMailer. Den kann man auch direkt nutzen und der könnte dann auch das, was Du brauchst.

    Warum die MailHelper-Klasse? Woher kommen die im Code gezeigten Konstanten wie MAIL_FROM_ADDRESS oder MAIL_FROM_NAME?

    Liebe Grüße

    Felix Riesterer

    1. Hallo Felix,

      einerseits ist es guter technischer Brauch, Schnittstellen zu anderen Systemen einzukapseln. Das verbessert die Testbarkeit und kann Austausch oder Anpassungen erleichtern. So auch hier.

      Andererseits ist der MailHelper etwas verunglückt, wenn er bestimmte define()s voraussetzt und sie verwenden will, ohne zu testen, ob sie existieren.

      Inhaltlich hat wohl tk alles nötige gesagt, sofern "Passwort" genug PHP versteht, um das einzubauen. Ich empfehle ein Backup der alten Implementierung 😉

      Rolf

      --
      sumpsi - posui - obstruxi
    2. Deine MailHelper-Klasse verwendet den PHPMailer. Den kann man auch direkt nutzen und der könnte dann auch das, was Du brauchst.

      Ok, gut zu wissen :-)

      Warum die MailHelper-Klasse?

      Ganz einfach: Weil der Programmierer das so gemacht hat 😉 Ich hatte mir mal vorgenommen, vieles zu vereinfachen, bin aber nicht dazu gekommen.

      Woher kommen die im Code gezeigten Konstanten wie MAIL_FROM_ADDRESS oder MAIL_FROM_NAME?

      Sind globale Variablen, die in einer Configdatei deklariert sind. Es ist mein Name und die Adresse für das Senden der Nachricht.

      Ich habe das jetzt aufgrund Hinweisen so gelöst: die Mailhelper habe ich so geändert:

      public function handleMail(string $subject,
                                     string $body,
                                     string $to_address,
                                     string $to_name,
                                     string $from_address,
                                     string $from_name,
                                     ?string $reply_to = null): PHPMailer
      ...
                  if ($reply_to) {
                      $this->mail->addReplyTo($reply_to, $from_name);
                      $from_name = MAIL_FROM_NAME;
      
      ...
      
       public function toAdmin(string  $subject,
                                  string  $body,
                                  ?string $from_address = null,
                                  ?string $from_name = null,
                                  ?string $reply_to = null): PHPMailer
      
      ...
      
              return $this->handleMail(
                  subject: $subject,
                  body: $body,
                  to_address: MAIL_TO_ADDRESS,
                  to_name: MAIL_TO_ADDRESS_NAME,
                  from_address: $from_address,
                  from_name: $from_name,
                  reply_to: $reply_to
              );
      

      Und den Sendevorgang so:

      
                      $mail->toAdmin(
                          subject: 'xxx',
                          body: 'yyy',
                          'Nachricht: ' . $message,   
                           from_name: $name, 
                           reply_to: $email  
                      )->send();
      

      Das klappt jetzt auch so wie gewünscht mit dem Senden. Frage: Ist das konform zu envelope-from?

      1. Liebe(r) Passwort,

                    if ($reply_to) {
                        $this->mail->addReplyTo($reply_to, $from_name);
                        $from_name = MAIL_FROM_NAME;
        

        mit $this->mail greifst Du auf eine Instanz des PHPMailers zu, die in Deiner MailHelper-Klasse in der Eigenschaft mail hinterlegt ist. Folgerichtig verwendest Du dann deren addReplyTo()-Methode, um den passenden Header zu setzen.

        Warum Du aber dann in der nächsten Zeile eine lokale Variable $from_name mit dem Inhalt der Konstanten MAIL_FROM_NAME befüllen must, verstehe ich nicht. Wozu genau brauchst Du eine lokale Variable mit fast gleichem Namen und identischem Wert, wenn Du stattdessen auch die Konstante verwenden könntest? Liegt das daran, dass Du vorübergehend einen vielleicht anderen Wert in $from_name abgelegt hast? Ich hätte nämlich folgende Zeile erwartet:

        $this->mail->addReplyTo($reply_to, MAIL_FROM_NAME);
        

        Oder verstehe ich Deine Konstanten noch falsch?

        Und den Sendevorgang so:

        
                        $mail->toAdmin(
                            subject: 'xxx',
                            body: 'yyy',
                            'Nachricht: ' . $message,   
                             from_name: $name, 
                             reply_to: $email  
                        )->send();
        

        Warum braucht es im toAdmin()-Aufruf den Parameter $from_name, wenn es eine Konstante MAIL_FROM_NAME gibt?

        Das klappt jetzt auch so wie gewünscht mit dem Senden. Frage: Ist das konform zu envelope-from?

        Wenn Du den entsprechenden Header im Quelltext der erhaltenen Mail findest, und wenn dessen Inhalt formal korrekt ist, dann ja. Diese Seite beschreibt (auf englisch) den Unterschied zwischen dem From-Header und dem X-Env-From-Header. Auch in der (deutschen) Wikipedia gibt es etwas zu Envelope Sender.

        Liebe Grüße

        Felix Riesterer

        1. Warum braucht es im toAdmin()-Aufruf den Parameter $from_name, wenn es eine Konstante MAIL_FROM_NAME gibt?

          Ich gehe mal davon aus, für mehr Flexibilität? Wenn man direkt die globale Variable nutzen würde, hätte ich nicht die Mailadresse des Absenders als from eintragen können, worum es hier ja geht.

          Wenn Du den entsprechenden Header im Quelltext der erhaltenen Mail findest, und wenn dessen Inhalt formal korrekt ist, dann ja. Diese Seite beschreibt (auf englisch) den Unterschied zwischen dem From-Header und dem X-Env-From-Header. Auch in der (deutschen) Wikipedia gibt es etwas zu Envelope Sender.

          Mein Provider behauptet, nach der Umstellung würde auch ein reply-to mit einer Domain, welche nicht in meinem Paket der Domains, die ich besitze, vorhanden ist, nicht mehr funktionieren. Deine beiden Links gehen auf diese vom Provider genannten Einschränkung nicht ein, vielmehr behaupten die, man könnte weiter einen falschen Absender angeben. Folglich wäre die bequeme Methode, dass wenn ich ein Mail von meiner Webseite bekomme, einfach mittels "antworten" dem Absender antworten kann, nicht mehr möglich.

          1. Liebe(r) Passwort,

            Mein Provider behauptet, nach der Umstellung würde auch ein reply-to mit einer Domain, welche nicht in meinem Paket der Domains, die ich besitze, vorhanden ist, nicht mehr funktionieren.

            was genau bedeutet „funktioniert“? Soll das heißen, dass eine Mail, deren Adresse im reply-to-Header zu einer „fremden“ Domain gehört, als Spam klassifiziert wird? Oder dass diese Adresse vom Server entfernt bzw. verändert werden wird? Oder, dass sie abgewiesen wird?

            Dein Mailprovider wird den From-Header hoffentlich nicht entfernen oder verändern, denn der gehört zu einer grundsätzlichen Information in einer Mail. Ob man damit in einem Mailprogramm (oder einem Webinterface) mittels eines wie auch immer gearteten „Antworten“-Buttons bequem eine Antwort-Mail verfassen kann, kommt nicht auf den Provider an, sondern auf das Programm, mit dem die erhaltene Mail verarbeitet wird.

            Also: Was genau hat Dein Anbieter mit dem From-Header vor?

            Nicht jede Idee ist eine gute Idee und nicht jeder Provider entscheidet sich für sinnvolle Maßnahmen. Manchmal hat es einen Sinn, den Provider zu wechseln. Ob das hier anzuraten ist, wäre allerdings erst noch zu prüfen.

            Deine beiden Links gehen auf diese vom Provider genannten Einschränkung nicht ein, vielmehr behaupten die, man könnte weiter einen falschen Absender angeben.

            Die Links beschäftigen sich mit einer technischen Spezifikation, nicht mit einer Spam-Schutz-Maßnahme (D)eines Providers.

            Folglich wäre die bequeme Methode, dass wenn ich ein Mail von meiner Webseite bekomme, einfach mittels "antworten" dem Absender antworten kann, nicht mehr möglich.

            Diese Aussage ist absolut und deswegen Quark. Richtig ist: Es kommt darauf an. Und zwar auf die wesentlichen Details. Also liefere diese, damit man Deine Schlussfolgerung auf ihre Gültigkeit bzw. Richtigkeit hin überprüfen kann.

            Liebe Grüße

            Felix Riesterer

          2. Hallo

            Warum braucht es im toAdmin()-Aufruf den Parameter $from_name, wenn es eine Konstante MAIL_FROM_NAME gibt?

            Ich gehe mal davon aus, für mehr Flexibilität? Wenn man direkt die globale Variable nutzen würde, hätte ich nicht die Mailadresse des Absenders als from eintragen können, worum es hier ja geht.

            Wenn ich deine Aussage zu deinem Hostinganbieter richtig verstehe, will er, dass eine von deiner Website per Skript versendete E-Mail nur mit einer gültigen E-Mail-Adresse deiner Domain im From-Header versendet wird. Das ist nach meiner Erfahrung bei vielen Hostinganbietern gängig. Wenn du also eine eigene Adresse mit einer beim Hostinganbieter dir/deinem Paket zuordenbaren Domain als Absender (From) angibst, solltest du den Anforderungen des Hosters genügen können.

            Mein Provider behauptet, nach der Umstellung würde auch ein reply-to mit einer Domain, welche nicht in meinem Paket der Domains, die ich besitze, vorhanden ist, nicht mehr funktionieren.

            Das allerdings klingt schräg. Der Reply-To-Header ist nämlich genau dafür da, eine vom Absender abweichende Antwortadresse bereitzustellen. Ein E-Mail-Client wird, wenn man eine E-Mail mit Reply-To-Header beantwortet, die dort angegebene Adresse in das To-Feld einfügen. Dort sollte also die im Formular angegebene E-Mail-Adresse des Seitenbesuchers, der das Formular ausfüllt, drin stehen.

            Tschö, Auge

            --
            „Habe ich mir das nur eingebildet, oder kann der kleine Hund wirklich sprechen?“ fragte Schnapper. „Er behauptet, nicht dazu imstande zu sein“ erwiderte Victor. Schnapper zögerte (…) „Nun …“ sagte er schließlich, „ich schätze, er muss es am besten wissen.“ Terry Prattchett, Voll im Bilde
            1. Das allerdings klingt schräg.

              So richtig schräg finde ich das nicht: Reply-To wurde schon mal missbraucht, um vorzutäuschen, dass ein Mail von mir stammte. Während ich von einer blauen Partygesellschaft mit allerhand letalem und nichtletalem Spielzeug am Gürtel und schwarzen Westen besucht wurde und also gefesselt in der Küche saß wurde dann gottlob noch so eins verschickt, weshalb die feierwütige Gesellschaft wieder abzog.

              Mancher im Forum kennt ja meine früheren und aktuellen „Freunde“ die samt und sonders behaupten, sich ganz besonders rechtstreu zu verhalten...

              1. Lieber Raketenwilli,

                Mancher im Forum kennt ja meine früheren und aktuellen „Freunde“ die samt und sonders behaupten, sich ganz besonders rechtstreu zu verhalten...

                *grusel*

                Liebe Grüße

                Felix Riesterer

          3. Mein Provider behauptet, nach der Umstellung würde auch ein reply-to mit einer Domain, welche nicht in meinem Paket der Domains, die ich besitze, vorhanden ist, nicht mehr funktionieren.

            Dann richte eine Antwortaddresse einfach so ein, dass bei dieser eingehende Emails weitergeleitet werden. Das bietet auch fast jeder Hoster an.

            Mag ein Umweg sein, funktioniert aber so lange wie dein anderer Mailserverbetreiber nicht vermeint, dass Du Spam verschickst oder dass der Mailserver Deines Hosters also solchen verschickt.

            Was bei Formularen „nicht ganz unkritisch“ ist.

            Fazit: Formmailer sind 2. Wahl.

  2. Moin,

    Ich habe die Seite nicht selbst gecoded sondern jemand, dessen Tagesgeschäft das ist. Er hat für den Mailversand (SMTP) "MailHelper" verwendet. Das Tool hat nach meiner laienhaften Erkenntnis keine Reply-To Option.

    Da zum Mailversand im Prinzip PHPMailer verwendet wird gibt es die Möglichkeit Reply-To zu verwenden:

        public function handleMail(string $subject,
                                   string $body,
                                   string $to_address,
                                   string $to_name,
                                   string $from_address,
                                   string $from_name): PHPMailer
        { // […]
    	            $this->mail->setFrom($from_address, $from_name);
        // […]
    

    Hier sollte es reichen statt setFrom() die Methode addReplyTo() zu verwenden (die verwendeten Parameter sind die gleichen) bzw. per addReplyTo die Adresse der Person zu setzen und in setFrom() deine Adresse zu setzen.

    Gruß
    Tobias

  3. Hallo

    Nachdem das grosse php-Forum php.de geschlossen ist, bin ich auf der Suche nach einem neuen Forum, wo man mir kompetent bei PHP-Fragen helfen kann.

    nur so am Rande:

    ich nutze brav php.net und dann halt Sprache auf deutsch stellen.

    Liebe Grüße,

    Hans

    1. ich nutze brav php.net und dann halt Sprache auf deutsch stellen.

      Da ist meines Erachtens kein Forum...

      1. Hallo Passwort,

        Da ist meines Erachtens kein Forum...

        stimmt, und es hilft Dir auch wenig beim konkreten Problem. Es könnte Dir allerdings helfen, deine PHP-Kenntnisse zu verbessern und zu erkennen, dass dieser MailHelper nichts weiter ist als eine Hülle um PHPMailer.

        Relevant für eine Selbsthilfe wäre die Beschreibung des PHPMailers.

        Und Selfhtml ist zwar für seine breit aufgestellte Kompetenz (und weit schweifenden Threads) bekannt, doch PHP ist nicht unsere Kernkompetenz und Du kannst deshalb hoffen, aber nicht erwarten, PHP-Fragen gründlich beantwortet zu bekommen.

        Eins ist mir aufgefallen: Tobias meinte, du solltest in der handleMail-Methode die Zeile

        $this->mail->setFrom($from_address, $from_name);
        

        durch

        $this->mail->addReplyTo($from_address, $from_name);
        

        ersetzen. Das ist sicherlich ein Schritt zur Lösung, allerdings fehlt dann die from-Angabe. Du müsstest prüfen, ob die Mails damit sinnvoll ankommen. Eventuell brauchst Du setFrom und addReplyTo und musst bei setFrom deine eigene Mailadresse angeben (die auch dein Mailprovider ins X-Env-From einträgt).

        Rolf

        --
        sumpsi - posui - obstruxi
        1. doch PHP ist nicht unsere Kernkompetenz

          Hehe.

          Die Kompetenz in gewissen, sehr expliziten PHP-Foren beurteile ich nicht als „besser“.

          P.S.: Ich genieße gerade das Wochende in vollen Zügen.

          (Mainz → Kassel)