[FX.php List] Mass Mailing Techniques (CODE Extract)

Steve Hannah shannah at sfu.ca
Tue Mar 28 10:02:23 MST 2006


>
> That said, I'm very intrigued by the suggestion to use a FileMaker  
> script
> with img tags - although I'm a bit lost on the concept.  Perhaps  
> you can
> elaborate a bit - or provide a code sample.

Here is some untested code just to give you the idea.

Essentially you just need two scripts (or actions):
	1. One to generate an HTML table of all of the email addresses to  
send to.  Each email address will have an associated <img> tag whose  
src is the other script (or action).
         2. One that sends to a single email address and outputs an  
image to indicate success or failure.  You just need to have a  
"success.gif" image and a "failed.gif" image that is output by this  
script.

The code example below actually breaks this into 3 stages for  
security reasons.   It is not a good idea to have a script that sends  
an email to an arbitrary address based on a get parameter, so I make  
use of session variables to make sure that only the email addresses  
returned from the database can receive email - and i use a  
"requestid" to exist across requests so that the script that sends a  
single email "knows" which request it belongs to. -- these are just  
security things.

Common pitfalls to watch out for with this approach:

1. Because the "sendone" script outputs an image, error checking can  
be difficult (because if it fails or there is extra whitespace  
output, the image just won't load and you won't have any ideas what  
happened.  (The example below uses the web server's error log to  
write errors so you can check there to see what's going on).

2. Whitespace!.  Make sure that there is no whitespace (or anything  
else) output from the script prior to it attempting to send the  
image.  This would ruin the image headers.



Best regards

Steve Hannah

<?
session_start();

if (@$_POST['action'] == 'sendall'){
	// Display the main html status page for all of the mailings
	// This page will call the 'sendone' action for each email address  
by way of img tags.
	
	if ( !isset($_POST['requestid'] ) ) trigger_error("No request id  
found.", E_USER_ERROR);
	if ( isset( $_SESSION['emailADD_'.$_POST['requestid'] ) ){
		$emailADD = unserialize($_SESSION['emailADD_'.$_POST['requestid']]);
			// we need to unserialize the array of email addresses that was  
generated.
		// now $emailADD is an array of the email addresses that need to  
have mail sent.
	} else {
		trigger_error("No email addresses could be found in the session.",  
E_USER_ERROR);
	}
	
	echo '
		<html><body><h1>Sending Mail...</h1>
		
		<table>
			<thead>
				<tr><th>Email Address</th>
					<th>Status</th>
				</tr>
			</thead>
			<tbody>
			';
			
	foreach ( $emailADD as $address ){
		echo '<tr><td>'.$emailADD.'</td>
			<td>
				<img src="'.$_SERVER['PHP_SELF'].'?action=sendone&requestid='. 
$_POST['requestid'].'&address='.$address'" alt="Status"/>
			</td>
			</tr>
			';
	}
	echo '</table>
	
	</body>
	</html>
	';


} else if ( @$_GET['action'] == 'sendone' ){
	// This action sends a single email to the address specified in $_GET 
['address'].
	// Most of the code for this action pertains to error checking to  
make sure that this is not a hacking attempt and
	// that all of the data is there.

	$failed = false;
	// we are sending one email address.  This action is always  
requested as an image so it should output an image
	if ( !isset($_GET['address']) ) {
		$failed = true;
		error_log("No address was specified for the email", E_USER_ERROR);
	}
	if ( !isset($_GET['requestid']) ) {
		$failed = true;
		error_log("No request ID found", E_USER_ERROR);
	}
	if ( isset($_SESSION['emailADD_'.$_GET['requestid']) ){
		$emailADD = unserialize($_SESSION['emailADD_'.$_GET['requestid']]);
		if ( !in_array($_GET['address'], $emailADD) ) {
			$failed = true;
			error_log("The specified address '".$_GET['address']."' was not in  
the list of addresses to be mailed for this request.");
		}
	} else {
		$failed = true;
		error_log("The specified requestid '".$_GET['requestid']."' could  
not be found in the session vars.");
	}
	
	if ( !mail($_GET['address'], $subject, stripslashes($body), "From: 
$from\nReply-To:me\nContent-Type: text/html") ){
		$failed = true;
		error_log("Failed to send mail to ".$_GET['address']." because  
there was a problem with the call to the mail() function");
	}
	
	if ( $failed){
		$img = "failed.gif";  // the path to an image to be used as the  
"failed" message
	} else {
		$img = "success.gif"; // the path to an image to be used as the  
success message
	}
	$fh = fopen($img);
	if ( !$fh ){
		error_log("Could not open image '$img'");
		exit;
	}
	header("Content-Type: image/gif");
	header("Content-Length: " . filesize($img));

	// dump the picture and stop the script
	fpassthru($fh);
	exit;
	

} else {
	// This is the default action..  This extracts the email addresses  
from the database
	// and places them in the $_SESSION array so that they can be used  
by the next incarnation
	// of the script.

	$requestid = rand(1000000);
		// generate a new request id


	// ... This is where you make your database request to get the  
member data ...

	foreach( $fmORGMEMBERdata['data'] as $key => $orgMEMBERS) {
	
		// Load array with only those individuals whom we have an email
		// address.  (Previously validated email addresses).
	
		if ((strlen($orgMEMBERS['OrgMemUSERDATA::email'][0])>0) &
	
			// Part of our criteria for selection includes a
			// check if the individuals title is within the
			// selection criteria, unless we've decided to send to
			// ALL members.
	
			(in_array($orgMEMBERS['title'][0],$roles) ||
	in_array('ALL',$roles))) {
		
	$emailADD[$mailCOUNT]=$orgMEMBERS['OrgMemUSERDATA::email'][0];
				$mailCOUNT++;
		}  // End of check
	} // End of Array Load
	
	// Save the email addresses in a session variable so that they can  
be accessed by subsequent pages.
	$_SESSION['emailADD_'.strval($requestid)] = serialize($emailADD);
	?>
	<html><body><h2>Found <?=count($emailADD)?> addresses for mailing.</h2>
	
	<form action="<?=$_SERVER['REQUEST_URI']?>" method="POST">
	<input type="hidden" name="requestid" value="<?=$requestid?>">
	<input type="hidden" name="action" value="sendall">
	<input type="submit" value="Send Now">
	</form>
	</body>
	</html>
	
	<?
}
?>


----------------------------------------
Steve Hannah
Web Services Developer

Faculty of Applied Sciences
Simon Fraser University
shannah at sfu.ca
604-268-7228
Homepage: http://www.sjhannah.com





More information about the FX.php_List mailing list