Viele personalisierte Newsletter (mehr als 1500) gleichzeitig versenden

Mein Vorschlag:
PHP:
<?php

	if( $_SERVER['REQUEST_METHOD'] != 'POST' || !isset($_POST['guid']) || $_POST['guid'] != php_logo_guid() ) {
		header('HTTP/1.1 400 Bad Request', true, 400);
		exit;
	}

	$_recordCount = 10;
	$_POST['offset'] = ( isset($_POST['offset']) && intval($_POST['offset']) >= $_recordCount )
		? intval($_POST['offset'])
		: 0;


	$_headerFields = array(
		'MIME-Version' => '1.0',
		'Content-Type' => 'text/plain; charset=iso-8859-1',
		'From'         => 'test-versand <test@stuvwxyz.de>'
	);
	$_additionalHeader = '';
	foreach( $_headerFields as $key => $value ) {
		$_additionalHeader .= $key . ': ' . $value . chr(0x0D).chr(0x0A);
	}

	$query = '
		SELECT
		        …
		  FROM
		        …
		  ORDER BY
		        `id`
		  LIMIT
		        '.$_POST['offset'].', '.$_recordCount.'
		';
	$result = mysql_query($query)
		or die(mysql_error());
	while( $row = mysql_fetch_assoc($result) ) {
		if( mail($to, $subject, $body, $_additionalHeader) ) {
			$_POST['offset']++;
		} else {
			break;
		}
	}
	$fp = fsockopen($_SERVER['HTTP_HOST'], $_SERVER['SERVER_PORT'], $errno, $errstr, 3);
	if( $fp ) {
		fputs($fp, "POST ".$_SERVER['PHP_SELF']." HTTP/1.0\r\n\r\n");
		fputs($fp, 'guid='.php_logo_guid().'&offset='.$_POST['offset']);
		fclose($fp);
	}
	exit;

?>
 
Hallo Gumbo,

Vielen Dank, das funktioniert - mit den derzeit 30 Adressen in meiner Test-DB - erstmal. Aber da ich sowas gern vollständig verstehe, hab' ich noch drei Fragen:

1. Diese Syntax ist mir unbekannt:
Gumbo hat gesagt.:
PHP:
	$_POST['offset'] = ( isset($_POST['offset']) && intval($_POST['offset']) >= $_recordCount )
		? intval($_POST['offset'])
		: 0;
Was bedeutet das genau?

2. Was hat das mit dem PHP-Logo zu bedeuten?

3. Zu fsockopen() hab' ich im PHP-Handbuch nachgelesen, werde aber nicht so richtig schlau daraus. Seh' ich das richtig, dass damit beim Aufruf der Funktion die Verbindung zum Server neu hergestellt und damit das Servertimeout umgangen wird?
Wenn ich das dann richtig verstehe, passiert das aber alles nach der while-Schleife, also nachdem das Script die ganzen Emails versendet hat. Macht das dann noch Sinn?

Danke schonmal:
27apricot
 
Zur ersten Frage: Die dortige Syntax ist der so genannte ternäre Operator (? … :). Es wird geprüft, ob die Variable einerseits existiert und andererseits einen Integer-ähnlichen Wert besitzt, der größer-gleich der abzufragenden Anzahl von Datensätzen ist.

Zur zweiten Frage: Es soll eigendlich der Verifizierung der Anfrage dienen. Ich weiß allerdings nicht, ob dessen Wert serverabhängig ist oder nicht. Falls nicht, wäre dieses Feature vielleicht obsolet.

Zur dritten Frage: Nein, damit wird eine Post-Anfrage gesendet und damit das Skript mit aktualisierten Parametern selbstaufgerufen. Und ja, es ergibt Sinn.

Ich hab’ meinen Skript-Vorschlag übrigens noch etwas geändert.
 
Hallo Gumbo,

hab' dein Script jetzt mehrmals mit 380 Email-Adressen ausprobiert. Es hat das Email nie an alle verschickt, da die Verbindung vorher vom Server abgebrochen wurde.

Dafür hat mir dein Script aber die Lösung für das kleine Problem, dass ich mit meinem Vorschlag hatte, geliefert: das erste OFFSET (dass ich per $_GET übergebe) muss '0' und nicht '1' sein.

Gibt es irgendetwas, was gegen meinen Entwurf spricht? Das einzige, was mir jetzt einfällt, ist, dass es VOR jeglicher Ausgabe ablaufen muss wegen der HEADER-Änderung. Aber das ist ja nur 'ne Kleinigkeit.

Schöne Grüße:
27apricot
 
So, da ich derzeit vor dem gleichen Problem stehe, hab das mit dem Offset und der Header Umleitung jetzt mal ausprobiert.

Der relevante Teil sieht so aus:

PHP:
		if($_GET["offset"]) {
			$offset = $_GET["offset"];
		} else {
			$offset = 0;
		}
		
		$per_durchgang = 10; //pro durchgang werden 10 newsletter verschickt
		
		// abfrage für die gesamtzahl der empfänger
		$sql_adr_anz = "SELECT id FROM newsletter_test";
		$res_adr_anz = mysql_query($sql_adr_anz) or die(mysql_error());
		
		if($offset < mysql_num_rows($res_adr_anz)) { // wenn offset kleiner als gesamtzahl		
		
			$query  = "SELECT email, vname, hash, id FROM newsletter_test LIMIT ". $offset .", ". $per_durchgang ."";
			$result = mysql_query($query);
			if(mysql_num_rows($result) > 0) {
				while ($row = mysql_fetch_array($result)) {
					
					// HTML body			
		
					$body = "<h1>Hallo " . $row["vname"] . "!</h1><br />";

					$body .= $text;
	
				
					// Plain text body (for mail clients that cannot read HTML)
					$text_body  = "Hallo " . $row["vname"] . "! \n\n";
					$text_body .= $text_body_txt;

		
					$mail->Body = $body;
					$mail->WordWrap = 60;
					$mail->AltBody = $text_body;
					
					$mail->AddAddress($row["email"]);
					
					if(!$mail->Send())
						header("Location: ../../../index.php?admin=newsletter&notsent");
		
					// Clear all addresses for next loop
					$mail->ClearAddresses();
					//$mail->ClearAttachments();
				}
				$offset += 10;
				header("Location: send.php?offset=$offset");
			} else {
				header("Location: ../../../index.php?admin=newsletter&sent");
			}
		}

Das Problem hierbei ist, dass er am Ende nicht auf die index.php weiterleitet (../../../index.php?admin=newsletter&sent), sondern sich in einer Endlosschleife mit folgendem Fehler aufhängt:
Code:
Fehler: Umleitungsfehler
Die aufgerufene Website leitet die Anfrage so um, dass sie nie beendet werden kann.
(So sagt halt der Firefox). Was ist da los?
 
Hallo diggity,

Meiner Meinung nach ist die if/else-Abfrage (die entscheidet, ob die Emails versendet werden und welcher header übergeben wird) unnötig. Gib doch einfach am Ende der Schleife HTML-Code aus, nach dem Motto: »Der Newsletter wurde erfolgreich versendet.« Durch die Abfrage, in der du $offset mit der Gesamtzahl der Empfänger vergleichst, wird der neue header erst ausgegeben, wenn alle Emails versendet wurden.

Ich weiß nicht, ob das dein Problem löst, aber ein Versuch wär's wert :)

Schöne Grüße:
27apricot
 
Zurück