Bei Problem: Mails kommen nicht an

Einklappen
Dieses Thema ist geschlossen.
X
Das ist ein wichtiges Thema.
X
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Bei Problem: Mails kommen nicht an

    Diskussion siehe hier

    Von Pekka
    Korrekturen und Erweiterungen von:
    onemorenerd
    -----------------------------------------------------------------------

    Mails kommen nicht an!

    Es kommt immer öfter vor, daß via PHP versandte Mails zwar versandt werden, beim Empfänger aber schlicht nicht ankommen.
    Das hat oft damit zu tun, daß automatisch generierte Mails durch Formfehler in den Headern oder im Inhalt von den inzwischen fast bei jedem Empfängerpostfach anzutreffenden Spam-Filtern fälschlich als ebensolcher erkannt und in einen Müll-Ordner wegsortiert, zurückgeschickt oder - noch schlimmer - kommentarlos gelöscht werden.

    [color=red]
    Die hier vorgestellten Lösungsansätze implizieren Änderungen am Code. Hier gilt das Selbstverständliche: Vorher Sicherungskopien anlegen und bei Massenversand-Skripten wie Newslettern UM HIMMELS WILLEN zweimal überprüfen, daß im Verteiler nur eigene Adressen stehen. Es gibt nichts peinlicheres, als wildfremden Newsletter-Abonnenten einen Nachmittag lang Müll-Mails zu schicken.[/color]


    Als Basis-"Werkzeug" sollte der Entwickler immer einen Mail-Account bei einem oder mehreren Freemailern zur Hand haben, der einfachen Zugriff auf die als Spam ausgefilterten Mails erlaubt, z.B. GMX. Das hat den Vorteil, daß man sein Mailskript gegen die jeweils aktuellste Spamfilter-Technologie testen kann, von der man bei den meisten großen Freemailern ausgehen kann. Zum Anderen hat man damit ein Empfängerpostfach an einem neutralen Ort, der nichts mit der eigenen Website, dem eigenen Server und so weiter zu tun hat. Kommt die Mail hier an, hat man es geschafft.

    1. Basis-Debugging für Einsteiger

    1.1 Weg mit dem at
    @mail() ist tabu

    Zuallererst schauen wir nochmal ganz genau nach, ob sich vor den Mail()-Befehl nicht während der Programmierung ein @-Zeichen geschlichen hat, das eventuelle Fehlermeldungen unterdrückt. Falls ja: Sofort entfernen und nochmal probieren.
    Gibt es jetzt eine Fehlermeldung, liegt das Problem hier. Probleme mit Mail() sind jedoch nicht Thema dieses Stickies.

    1.2 Der kleine Unterschied

    $_GET und $_POST - ein tolles Team

    Ein Kontaktformular aus einem älteren Projekt versendet nur noch leere oder gar keine Mails mehr? Ein Kontaktformular-Skript funktiniert nicht? Dann hat vielleicht der Provider gewechselt oder stillschweigend register_globals abgeschaltet, was der alten Schreibweise für Requestvariablen (z.B. "$mail" statt $_GET['mail']") den Hahn abdreht. Also: Erstmal überprüfen, ob die an den mail()-Befehl übergebenen Variablen überhaupt etwas enthalten. Ein Skript nach dem Muster...

    PHP-Code:
    <? 

    $empfaenger = "mustermann@mustermann.de";

    mail ($empfaenger, "Mail von Kontaktformular", $nachricht);

    ?>
    ... erweitern wir so, daß die Werte, die der Mail()-Befehl gesagt bekommt, als HTML ausgegeben werden:

    PHP-Code:
    <? 

    $empfaenger = "mustermann@mustermann.de";
    $betreff = "Mail von Kontaktformular";

    mail ($empfaenger, $betreff, $nachricht);
    echo "Empfänger: $empfaenger<br>";
    echo "Betreff: $betreff<br>";
    echo "Nachricht: $nachricht";

    ?>
    ... Wenn nach einem erneuten Aufruf der Absendeseite dann Werte neben "Empfänger", "Betreff" und so weiter ausgegeben werden, ist alles in Butter und Du kannst die Testzeilen wieder löschen. Wenn nicht, hast Du den Fehler schon gefunden.


    2. Diagnose

    2.1 Rohrkrepierer oder Missing In Action?
    Rausfinden, ob die Mail den Server verlassen hat oder nicht

    Also. Der Mail()-Befehl gibt keinen Fehler aus, die obengenannten Flüchtigkeitsfehler liegen nicht vor, und die Mails kommen einfach nicht an. Jetzt müssen wir durch "Trial and error" rausfinden, woran das liegt: Werden die Mails gar nicht erst versandt, oder lauert ihnen auf dem Weg zum Empfänger ein Spamfilter auf? Wenn Du schon definitiv weißt, daß Deine Mails einem Filter zum Opfer fallen (z.B. weil Du von den Empfängerservern entsprechende Rückmeldungen bekommst), kannst Du gleich zu Punkt 3 springen.

    Um herauszufinden, wo das Problem genau liegt, brauchst Du Zugang zu einem Postfach, das NICHTS mit dem versendenden Server zu tun hat, am besten einen Freemail-Account bei einem Provider, der einfachen Zugriff auf die als Spam ausgefilterten Mails bietet, z.B. GMX (Dort heißt der entsprechende Ordner "Spamverdacht"). Nimm dein Versandskript, und laß es eine Mail an das Postfach versenden. Warte ein paar Minuten.
    Wenn Deine Mail dann weder im Posteingang noch im Spamverdacht-Ordner zu finden ist, und im Postfach der vom Versandskript angegebenen Absenderadresse keine Fehler-Mail angekommen ist, liegt der Verdacht nahe, daß die Testmail den Server gar nicht erst verlassen hat. In dem Fall wende Dich an den Administrator des Servers - wenn Du das angibst, was Du bisher probiert hast, sollte dich selbst die unwilligste Providerhotline
    ernstnehmen. Viele brauchbare Tipps bei Mail-Versandproblemen finden sich auch in den User Contributed Notes zum Mail()-Befehl.
    Landet die Mail beim Freemailer aber im Spam-Ordner, hast Du definitiv ein Spamproblem. Dann weiter zu Punkt 3.

    2.2 Lokalkolorit oder: was habt ihr denn alle?

    Wenn der umgekehrte Fall vorliegt, also Du problemlos den Newsletter über dein Versandskript erhältst, die Empfänger sich aber darüber beklagen, daß bei ihnen nichts ankommt, solltest Du folgendes bedenken: Wenn Du den Output deines Skripts auf der Website mustermann.de mit einer Test-Mail an Dein Postfach info@mustermann.de überprüfst, wird sie (weil versendender und empfangender Server derselbe sind) als "lokale" Mail behandelt und sofort im entsprechenden Postfach abgelegt. Ein Beweis dafür, daß Mails den Server richtung Internet verlassen, ist das noch lange nicht. Teste das ganze, wie oben beschrieben, mit einem externen Postfach bei einem Freemailer.

    3. Therapie

    Die Mail wird also mit großer Sicherheit versandt, kommt aber beim Empfänger nicht an.
    Die häufigsten Ursachen, warum automatisch generierte Mails als Spam ausgefiltert werden:

    3.1 "From" und "Reply-To"

    Oft gibt es den Fall, daß Kontaktformulare mit der Adresse als Absenderadresse ausgestattet werden, die ein Benutzer beim ausfüllen des Formulars angegeben hat - zumeist für erhöhten Komfort, damit der Empfänger des Formulars durch einen Klick auf "Antworten" mit dem Versender in Kontakt treten kann. Hier gilt: Wenn eine E-Mail eine Absenderadresse enthält, deren Domain-IP nicht zum versendenden Domain zu tun hat, besteht erhöhte Gefahr, von einem Spamfilter abgefangen zu werden. Ein Mailskript auf der Domain mustermann.de sollte als "from"-Adresse also unbedingt eine Adresse nach dem Muster info@mustermann.de enthalten. Um den ursprünglichen Komfort zu erhalten, gibt man die fremde Antwortadresse als "reply-to"-Angabe mit:

    mail ("empfaenger@xyz.de", "Mail von Kontaktformular", $nachricht, "from: Mustermann.de Server <info@mustermann.de>\r\nreply-to: ".$email);

    Einzelne Header-Zeilen sollten generell mit \r\n voneinander getrennt werden.

    3.2 Schlechter Umgang und die Folgen
    Mail-Blacklists

    Blacklists sind Listen von IP-Adressen, die in der Vergangenheit durch den Versand von Spam aufgefallen sind. Viele Spamfilter fragen beim Überprüfen von Mails eine solche Blacklist ab. Überprüfe, ob die IP deiner Website in einer solchen Blacklist steht - gerade bei Shared-Hosting-Angeboten kann es sein, daß sich ein Nachbar danebenbenommen hat und jetzt alle anderen, die sich den Server teilen, dafür durch die Listung der gemeinsamen IP-Adresse in einer solchen Blacklist abgestraft werden.
    Sollte das der Fall sein, wende dich an den jeweiligen Blacklist-Betreiber und Deinen Provider.
    Eine Sammlung von Blacklists findest Du z.B. hier. Ein Tool zum bequemen Abfragen vieler Blacklists auf einmal findest Du hier.

    Versuchst Du, Mails von Deinem lokalen Testserver aus, der via DSL im Netz hängt, zu verschicken, kannst Du das übrigens aus genau diesem Grund gleich vergessen. Mails von Dialup-IPs werden von Spamfiltern gnadenlos gefiltert.

    3.3 Spamfilter packen aus! - ihre intimsten Geheimnisse, ihre brutalen Methoden.

    Die Spamfilter einiger Freemailer erklären dem Benutzer, warum eine Mail als Spam ausgefiltert wurde. Das kann bei der Fehlerbehebung sehr hilfreich sein.
    Das sieht bei GMX z.B. so aus:


    3.4 Nummer Fünf lebt!

    In neueren (nach 2004 gebuchten) Shared-Hosting-Angeboten eines großen Webhosting-Anbieters kommt es regelmäßig vor, daß die Absenderadresse der Mail über den fünften Parameter der mail()-Funktion, der Anweisungen direkt an das meistens hinter den PHP-Kulissen werkelnde sendmail übergibt, nach dem Muster "-f absender@domain.de" übergeben werden muß - ansonsten wird die Mail offensichtlich gar nicht abgeschickt, aber auch keine Fehlermeldung übergeben. Was das für einen Sinn machen soll, weiß ich nicht. Mehr zu sendmail und "-f" gibts hier.
    Aus einem nicht funktionierenden

    Code:
    mail("{empfaenger@domain.de}", "{Betreff}", "{Mailtext}",
     "{eventuell vorhandene Header}")
    lohnt es sich also, mal Testweise ein

    Code:
    mail("{empfaenger@domain.de}", "{Betreff}", "{Mailtext}", 
    "{eventuell vorhandene Header}", "-f [email]absender@domain.de[/email]")
    zu machen und zu schauen, ob das funktioniert.
    Zuletzt geändert von pekka; 21.03.2006, 20:58.

  • #2
    E-Mailversand absichern und SPAM-Versand verhindern - Mailinjections

    Viele glauben, dass die meisten von PHP-Programmierern fabrizierten Sicherheitslücken bei include, require oder bei mySQL-Queries liegen. Doch dem ist nicht so - denn gerade die Spammer nutzen unsichere Formulare aus, um ihre ungeliebten Werbenachrichten über fremde Server zu versenden.

    1. Die Sicherheitslücke
    Viele Programmierer, vor allem Neulinge, verwenden die mail()-Funktion von PHP, mit der bequem E-Mails versendet werden können, beispielsweise über ein Kontaktformular.
    Ein Blick in das Manual zeigt:
    bool mail ( string to, string subject, string message [, string additional_headers [, string additional_parameters]] )
    Empfänger, Betreff, Nachricht, optional sogar noch zusätzliche Header bzw. zusätzliche Parameter für den Mailserver können hier an die Funktion übergeben werden.

    Ein typisches Kontaktformular könnte z.B. diesen Aufbau enthalten:

    Name:
    E-Mail:
    Betreff:
    Nachricht:

    Der Aufruf der Mail-Funktion könnte demnach in etwa so aussehen:

    PHP-Code:
    mail('admin@website.com'$_POST['betreff'], $_POST['nachricht'], 'FROM: '.$_POST['email']); 
    Damit würde an eine fest vorgegebene Adresse (admin@website.com) immer die E-Mail gesendet, mit Betreff, Nachricht und E-Mail des Absenders.

    1.1 Das Problem

    Der häufig unterschätzte Fehler ist, dass die Daten nicht auf ihre Korrektheit überprüft werden, sondern direkt an die mail()-Funktion übergeben werden.
    Spammer suchen nach solchen Formularen und nutzen diese systematisch aus.

    1.2 Die Ursache
    Nach RFC2822 ist der Aufbau einer E-Mail festgelegt - sie muss einen Header und Body enthalten, wobei der Body mit der Nachricht gleichbedeutend ist. Die Nachricht kann auch leer sein.

    Original von http://www.faqs.org/rfcs/rfc2822.html
    Messages are divided into lines of characters. A line is a series of
    characters that is delimited with the two characters carriage-return
    and line-feed; that is, the carriage return (CR) character (ASCII
    value 13) followed immediately by the line feed (LF) character (ASCII
    value 10). (The carriage-return/line-feed pair is usually written in
    this document as "CRLF".)

    A message consists of header fields (collectively called "the header
    of the message") followed, optionally, by a body.
    The header is a
    sequence of lines of characters with special syntax as defined in
    this standard. The body is simply a sequence of characters that
    follows the header and is separated from the header by an empty line
    (i.e., a line with nothing preceding the CRLF).
    Das fett hervorgehobene ist hierbei für uns von besonderer Bedeutung - denn exakt diese "Schwäche" wird von den Spammern ausgenutzt.
    Insbesondere ist zu beachten, dass der Header und Body mit einer Leerzeile voneinander getrennt sind.

    2. Der Angriff

    Versetzen wir uns in die Perspektive eines Angreifers. Er wird mit Sicherheit zuerst einmal das Formular auf seine Sicherheit überprüfen, indem er Daten einfüllt, auf die das Script hoffentlich nicht vorbereitet ist.
    Beispielsweise könnte er in das Feld 'Absender' folgende Daten eingeben (zu beachten ist hierbei, dass es keine Rolle spielt, wie die Felder in einem Internetbrowser dargestellt werden!)

    bla@test.de
    Subject: Unser neues Angebot
    To: mail@empfaenger.com
    bcc: mehrempfaenger@domain.com

    Unser neues Angebot! Jetzt kaufen!
    In die anderen Felder füllt er beliebige (vielleicht sogar sinnlose) Werte ein.

    Dadurch, dass wir ungeprüfte Parameter an die Mailfunktion übergeben, wird nun als Headerinformationen übergeben:

    FROM: bla@test.de
    Subject: Unser neues Angebot
    To: mail@empfaenger.com
    bcc: mehrempfaenger@domain.com

    Unser neues Angebot! Jetzt kaufen!
    Der 1. Teil ist der Header - und wie wir oben gelernt haben, sind Header und Body mit einer Leerzeile voneinander getrennt, genau wie hier. Das heißt also, dass nun der eigentliche Header-Parameter von mail() bereits dazu benutzt wurde, auch Body-Informationen anzuhängen.
    Alle anderen Informationen aus dem Kontaktformular werden nun lediglich an den Body angehängt - nicht an den Header, wie eigentlich beabsichtigt. Durch die Kontrolle über den Header hat man nun auch die Kontrolle über den Empfänger - der fest eingestellte Empfänger wird ignoriert und stattdessen an beliebige Empfänger versendet.


    2.1 Abhilfe schaffen

    Abhilfe schafft man, indem man die Daten vorher überprüft und nicht direkt an mail() übergibt.
    So sollte man z.B. per str_replace jedes Vorkommen von \r und \n in der E-Mailadresse ersetzen.
    PHP-Code:
    str_replace(array("\r""\n"), ''$_POST['absender']); 
    Optimal wäre es natürlich, generell auf eine korrekte E-Mailsyntax zu überprüfen und gegebenenfalls eine Fehlermeldung auszugegeben sowie die Mail nicht abzusenden. Ungeprüfte Daten sind eine große Sicherheitsücke und können schnell dazu führen, dass der eigene Server als SPAM-Schleuder missbraucht wird!


    3. Die hidden-field Methode...

    ... sollte man nie verwenden.

    Hierbei handelt es sich um Formulare, die bereits ein verstecktes input-field enthalten, in denen der Empfänger enthalten ist.

    Das könnte z.B. so aussehen:
    Code:
    <input type="hidden" name="reciever" value="meinemail@domain.com" />
    Ein mail()-Aufruf könnte dann so aussehen:
    PHP-Code:
    mail($_POST['reciever'], $subject$message'FROM: '.$from); 
    Das wird gerne von Programmierern dazu verwendet, eine mySQL-Datenbankabfrage beim versenden zu sparen - schließlich muss der Empfänger nicht mehr aus der Datenbank herausgeholt werden.
    Das Problem hierbei ist jedoch, dass HTML-Code für jedermann einsehbar ist - und natürlich auch manipulierbar. So könnte ein Spammer jeden beliebigen Absender in das hidden-field schreiben (und somit den vom Programmierer eingetragenen Empfänger einfach überschreiben) und auch so das Formular für seine Zwecke missbrauchen. Ein Angriff über den Header ist somit unnötig geworden.


    Fazit
    1. Daten niemals ungeprüft an mail() übergeben, auf Carriage-Returns (\r) und Newlines (\n) überprüfen.
    2. Keine hidden-felder für wichtige Daten verwenden - diese können eingesehen und leicht manipuliert werden!

    Wenn man sich an solche grundlegenden Regeln hält, macht man es den Spammern schon wesentlich schwieriger, die eigene Website für ihre Zwecke zu missbrauchen....
    Für alle die Fehler suchen, gibts gratis tolle Debuggingmöglichkeiten:
    var_dump(), print_r(), debug_backtrace und echo.
    Außerdem gibt es für unsere Neueinsteiger ein hervorragendes PHP Tutorial zu PHP 4 und PHP 5 (OOP)
    Es heißt $array['index'] und nicht $array[index]! Und nein, das ist nicht egal!
    Dieses Thema lesen, um Ärger im Forum und verzögerte Hilfen zu vermeiden.

    Kommentar

    Lädt...
    X