Selbstgebackenes Mailer Script in PHP

PH

Legendäres Mitglied
Hallo Forum

Ich habe selbst ein Script zum Verschicken eines Newsletters geschrieben (wird über Cron Job alle 5 Minuten gestartet).

Meine Tests verliefen soweit erfolgreich. so konnte ich z.B. das Mail auf meiner GMX-Adresse empfangen, ohne dass es im SPAM-Ordner landete.

Das Script habe ich sehr einfach gehalten.
Es verwendet Sendmail mit den Parametern from,to,subject und body.

In anderen Mailern habe ich jedoch gesehen, dass noch Header hinzugefügt werden, und andere Informationen (z.B. reply-to Adresse).

Frage:
Was sollte (i.e. welche Header, Felder) im Idealfall alles in einer Mail enthalten sein, damit sie alle empfangen können?

 
hi

also du solltest mal die whitelist der unterschiedlichen anbieter lesen. bei aol z.B weiss ich das es sowas gibts. verschickst du viele mails an nutzern von aol, dann können sie deine mail sperren, ausser du hast deine domain in die whitelist eingetragen. kenne aber sonst kein anderen der sowas hat.

wichtig ist, dass du den abonnenten die möglichkeit gibst sich auszutragen oder daten zu ändern.

diese sollte auch lesbar sein, wenn man kein html aktiviert hat, in seinem mailprogy.

ich würde bilder auch nicht mit schicken, sondern diese von deinem server abholen lassen wenn sie erwünscht sind. die meisten lassen dies eh deaktiviert und somit ersparst du dir transfer kosten, falls du mal über 100.000 abonnenten hast.

grüsse
jeliel
 
Danke für die Tipps - diese Punkte sind wichtig, waren mir aber schon klar.

Meine Frage war eher technischer Art, welche Vorraussetzungen die Mails aus technisch-inhaltlicher Sicht erfüllen müssen, um anzukommen.

 
QUOTE (PH @ Di 13.2.2007, 10:30)In anderen Mailern habe ich jedoch gesehen, dass noch Header hinzugefügt werden, und andere Informationen (z.B. reply-to Adresse).

Frage:
Was sollte (i.e. welche Header, Felder) im Idealfall alles in einer Mail enthalten sein, damit sie alle empfangen können?

Das hängt davon ab, was man sonst noch alles mit der Mail machen möchte.

Ich verschicke Mails aus meinem System bsp. grundsätzlich über noreply @ sql-und-xml.de. Kunden können aber in ihrer Datenbank einen Reply-Namen und eine Reply-Mailadresse angeben, so daß als Versender


QUOTE "Reply-Name des Kunden" <noreply @ sql-und-xml.de>


und als Replyadresse beim Klick des Empfängers auf Reply


QUOTE "Reply-Name des Kunden" <hinterlegte Mailadresse des kunden>


erscheint. Ferner können bei mir bestimmte Mails einen zusätzlichen Header


QUOTE sd-bid: 9-15-2003-2-7D9A447E-FCDE-4F47-A6BA-B7AB075BEFC9


enthalten. Zum einen ist es mir unter Spamgesichtspunkten zu heikel, Mails von verschiedenen Versenderadressen + Domains von meinem Server her zu verschicken - so wird immer nur eine Adresse verwendet. Zum anderen kann das noreply-Konto automatisiert abgefragt werden - und findet bei einem SMTP-550-Fehler (ungültige Empfängermail) über den sd-bid-Schlüssel die zugeordnete Mailadresse und sperrt diese. Damit verschickt diese Logik nicht wiederholt Mails an dieselbe ungültige Mailadresse - das könnte Spamfilter triggern.
 
kannst du das mit dem 550er und dem header genauer erläutern wie das geht? plane ebenfalls einen mailversand aus meiner DB und hab schon genug probleme, weil anscheinend über meine domains mails verschicxkt wurden und meine mails nun bei diversen adressen nicht mehr ankommen...
 
QUOTE (radarin @ Di 13.2.2007, 12:45)kannst du das mit dem 550er und dem header genauer erläutern wie das geht?

Mein Mailserver (Microsoft SMTP-Server) schickt bei einer unbekannten Mailadresse eine dreigeteilte Mime-Mail zurück - einfacher Hinweistext, Statuscode gemäß dem SMTP-Protokoll und die verschickte Mail. Das Ergebnis muß man dann zerteilen - ein Header und den Body, dann prüfen, ob im zweiten Teil der 550 drinsteht. Und dann muß der dritte Abschnitt rekursiv als Mail mit Header und Body verarbeitet werden, dort wird aus dem Header der obige Schlüssel ausgelesen. Von da an sind das eigene Definitionen - 9 ist die Id meiner eigenen Testdatenbank, dann folgt die ID der Mailversende-Zeile, die ID der Spalte mit der Mailadresse (in einer Tabelle kann es mehrere solcher Spalten geben), die Zeilen-Id und schließlich ein Zufallsschlüssel, der zur Mailadresse gehört. Nur wenn der zu den restlichen Daten paßt, wird die Mail gesperrt.

Im wesentlichen steckt da nix besonderes dahinter, es ist halt eine etwas langwierige Fummelarbeit.


QUOTE (radarin @ Di 13.2.2007, 12:45)und hab schon genug probleme, weil anscheinend über meine domains mails verschicxkt wurden und meine mails nun bei diversen adressen nicht mehr ankommen...


Solange aber so etwas passiert, ist die Gesamtarchitektur nicht hinreichend sicher. Da würde ich mich erst um diese Sicherheit kümmern, bevor weitere, potentiell unsichere bzw. angreifbare Features installiert werden - und damit nur darauf warten, von anderen gehackt und ausgenutzt zu werden. Wie mal an einem Beispiel erläutert, kommen bei mir Hacker an der Stelle mit Mailheaderinjektionen nicht durch.
 
Das versenden per sendmail, bzw mail() ist nicht ganz simpel wenn man das ganze sauber lösen will. Richtig spannend wirds dann wenn es HTML-Mails werden sollten, oder Attachements..

Unter PHP bietet sich daher die PHPMailer-Klasse sehr gut an. Ist einfach einzubinden, und leistet saubere Arbeit..

Verschiedene Absenderadressen über einen SMTP-Server zu jagen ist nicht kritisch. Wichtig ist bloss dass dieser sauber konfiguriert ist (Reverse-Lookup etc..). Ansonsten landest du in der Tat sehr schnell (innert 1-2h) auf einer schwarzen Liste (spamhaus.org etc.).

Quoten auf einem Mailserver müssten Heute (hoffentlich) ein Standard sein (Mailbomben..)
 
Ich habe ein wenig an meinem Script weitergewerkelt.

Es ist sehr sequenziell und die Performance ist schlecht - das Script verursacht einen relativ hohen Load auf dem Server.

Wie würdet ihr das programmieren?

Mein Ziel ist, jede angemailte e-mail Adresse mit einem code zu versehen, damit keine zweite Mail dorthin geschickt wird.

Ich vermute, es sind die 100 Update Queries in jedem Loop, die den Load verursachen.

Wie würdet ihr das lösen?
Bringt BCC etwas? Wie bekommt man BCC hin?

CODE

/**** 100 Adressen erhalten, die noch nicht angemailt wurden ****/
$sql2 = 'select email from users where '.$query.' and (mail_codes is null or mail_codes not like "%'.$code.'%") limit 100';
$result2 = mysql_query($sql2);

$path_to_sendmail = "/usr/sbin/sendmail";
$from = "no_reply@abcdef123.com";

/**** Einzelne Mails an die Adressen schicken ****/

while($row = mysql_fetch_array($result2)) {
$to = $row['email'];
$fp = popen("$path_to_sendmail -t", "w");
$num = fputs($fp, "To: $to\n");
$num += fputs($fp, "From: $from\n");
$num += fputs($fp, "Subject: $subject\n\n");
$num += fputs($fp, "$message");
pclose($fp);

/**** Den Mailadresse-Record mit dem Versandcode markieren ****/

$marker = "-".$code;
$sql3 = 'update users set mail_codes = IF(mail_codes IS NULL, "'.$marker.'", Concat(mail_codes,"'.$marker.'")) where email="'.$to.'"';
$result3 = mysql_query($sql3);

/**** um den Load etwas zu verringern, warten wir eine Sekunde ****/
sleep(1);

}



$query ist eine where clause, die spezifische adressen eingrenzt
$code ist ein code, der diesen mailversand identifiziert
 
Zwei Hinweise:

- Ein Update von Textspalten, bei denen Text hinzugefügt wird, ist bei einem Füllfaktor von 100% sehr aufwendig: Ich gehe davon aus, daß auch mySql die Daten (wie der MS-SqlServer) in (bsp. 8 KB großen) Seiten ablegt, also muß eine Seite geladen, auf zwei Seiten aufgeteilt und die Texte eingefügt werden. Ein niedrigerer Füllfaktor könnte hier helfen.

- Die Daten sind nicht normalisiert. Damit muß doppelt gesucht werden (Null und Like '%' + aktueller Wert + '%'), diese Textsuche ist aufwendig.

Deshalb Alternative Daten normalisieren: Es müßte ja eine Tabelle mit den Mailversendeschlüsseln geben. Dann eine Verknüpfungstabelle zwischen dieser und der Tabelle mit den Mails, jedes Mailversenden erzeugt einen neuen (nun normalisierten) Eintrag in dieser Tabelle. Das läßt sich mit einem einfachen Select aus der Grundtabelle heraus erledigen - und geht normalerweise erheblich schneller als ein Update. Man muß dann lediglich beim Datenholen einen LeftJoin auf eine Unterabfrage (Select Id from Verknüpfungstabelle A Inner Join Mailversendegrundtabelle B On A.Spalte = B.Spalte Where B.Schlüssel = $Schlüssel) einbauen und diese ID auf Null prüfen.

QUOTE (Alonso @ Mi 14.2.2007, 0:59)Unter PHP bietet sich daher die PHPMailer-Klasse sehr gut an. Ist einfach einzubinden, und leistet saubere Arbeit..

Das ist witzig: Ein OpenSource-Projekt baut ein - längst schon veraltetes - Microsoft-Produkt nach:

QUOTE Uses the same methods as the very popular AspEmail active server (COM) component

Da bleibe ich doch lieber gleich beim Original.
 
Hallo JAuer

Danke für die Hinweise.

Die separate Tabelle mit den Mailversandcodes leuchtet mir ein.
Ich werde die Funktion des Scripts ändern.
Dann wird bei jedem einzelnen Mailversand ein zusätzlicher Record in der Mailversandtabelle angelegt.

Allerdings habe ich den ersten Punkt mit dem "Füllfaktor" nicht verstanden.
Ich interpretiere Deine Nachricht so, dass dieses Problem mit der Zusatztabelle verschwindet, jedoch bin ich neugierig und würde gerne verstehen, um was es bei dem "Füllfaktor" geht.
 
QUOTE (jAuer @ Do 15.2.2007, 18:17) Das ist witzig: Ein OpenSource-Projekt baut ein - längst schon veraltetes - Microsoft-Produkt nach:

QUOTE Uses the same methods as the very popular AspEmail active server (COM) component

Da bleibe ich doch lieber gleich beim Original.

Den PHPmailer gibts ja auch schon etwas länger, ist aber in meinen Augen noch immer die beste Variante unter PHP. Wenn du das Original (mail() ) dort kennen würdest, wärst auch du glücklich damit ..
wink.gif
 
QUOTE (PH @ Do 15.2.2007, 17:30)Allerdings habe ich den ersten Punkt mit dem "Füllfaktor" nicht verstanden.
Ich interpretiere Deine Nachricht so, dass dieses Problem mit der Zusatztabelle verschwindet, jedoch bin ich neugierig und würde gerne verstehen, um was es bei dem "Füllfaktor" geht.

Daten werden pro Tabelle nicht zeilenweise, sondern in Seiten (bsp. 8 KB) auf die Festplatte geschrieben - die Zellen einer Zeile sind aber i.d.R. zusammenhängend. Außerdem sind Daten meist über einen gruppierten Index (i.d.Regel der Primärschlüssel) sortiert abgelegt.

Wenn die Tabelle mit einem 100%-Füllfaktor erstellt wurde, dann enthält eine Seite von 8 KB auch 8 KB Daten. Wird eine Seite bsp. mit einem Füllfaktor von 50% reorganisiert (k.A., ob das mySql kann), dann wird doppelt so viel Platz auf der Festplatte benötigt - jede 8-KB-Seite enthält nur noch 4 KB Daten, zusätzlich gibt es freien Platz.

Wenn beim Update Text hinzugefügt wird und die Seite bereits voll ist, muß die Seite auf zwei Seiten aufgeteilt und alle internen Verweise müssen angepaßt werden - das erzeugt Sperren für alle Datensätze dieser Seite und benötigt Zeit - IO-Operationen. Wurde die Tabelle mit einem Füllfaktor von 50% erstellt und ist auf der Seite noch genügend Platz, genügt es, die nachfolgenden Datensätze auf dieser Seite nach hinten zu verschieben, um Platz zu gewinnen - das geht weitaus schneller. Deshalb werden Tabellen mit umfangreichen Update-Anweisungen gerne mit einem Füllfaktor von bsp. 50% erstellt und die Tabellen werden nächtlich (zu Zeiten geringer Auslastung) reorganisiert. Für Tabellen, bei denen nur hinzugefügt wird (bsp. Protokolltabellen) oder die nur konstant lange Spalten oder Verknüpfungsverweise (Datum, Fremdschlüssel als Integer - keine großen Textspalten) enthalten, ist das natürlich Unsinn - hier belegt ein neuer Datensatz genauso viel Platz wie jeder aktualisierte Datensatz.
 
Wow - danke für die Erklärung - jetzt habe auch ich es kapiert.

Ist wohl (vereinfacht gesagt) ähnlich der Fragmentierung von Dateien.
Ich frage mich, ob Datenbanken eventuell selbstdefragmentierend sein können, wie das Dateisystem XFS?
 
Zurück
Oben