Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

PHP Send To Mail List Script 1

Status
Not open for further replies.

PhoenixD

Programmer
Aug 19, 2007
21
US
Is there any popular scripts that are used to simply send to a mailing list?

Not trying to calculate bounces or anything fancy like that, should support a couple thousand people on the list.

I know of PHPList, but that's WAY overboard, I literally just need to be able to point at a database saying "here are names and emails" and send a message.

Any ideas? Preferably looking for a free solution, but not necessarily.

Would it be easier to program one?

Thanks!
 
this piqued my interest a bit so i wrote a quick class.

to use it you need to set all the variables in the first method. they are fully commented so it should be obvious.

there is a usage example in the <code> tags at the top of the class.

note: i have more or less typed this straight into an editor. i have not tested it (even for syntax) so you will almost certainly have to debug heavily. I have also not written any log analysis routines, but at least the data will be there for you to review.

note that in order to use the tracking pixel you must include the text {TRACK} in the body of the html email message. ideally just before the </body> tag.

Code:
<?php
//require 'dbConnection.php'; //database connection script with mysql_connect and mysql_select_db

/**
 * class to mail shot a group of people
 * 
 * @example
 * <code>
 *  $mailer = NEW listMailer();
 *	if (isset($_GET['action']) && $_GET['action'] == 'getImage'){
 *		if (!empty($_GET['id']) && !empty($_GET['email'])){
 *			$mailer->track($_GET['uid'], 'mail opened', $_GET['email']);
 *		}
 *	}
 *	$text = 'I am a text based version of the email';
 *	$html = '<body><h2>Hello World</h2><p>I am an html version of the email</p>{TRACK}</body>';
 *  $subject = 'New Email';
 *  $mailer->setMessageInfo($subject, $text, $html);
 *  $mailer->sendToList();
 *	</code>
 */
$mailer = new listMailer();
class listMailer{
	
	
	/**
	 * method to construct the object
	 * 
	 * this method sets all the variables that are used in the class.  
	 * these properties/variables are predominanly user settable
	 */
	public function listMailer(){
		/*
		 * database level variables
		 */
		$this->dbTable = ''; //the table where the email addresses are to be found
		$this->nameCol = ''; // the table column in which the actual names of the recipients are to be found
		$this->emailCol = ''; //the table column in which the email addresses will be found
		
		/*
		 * mail server information
		 */
		$this->smtpHost = '';	//host name or IP address of the SMTP server.  
		
		/*
		 * other application level variables
		 */
		$this->logging = true;	//set to false for no logging
		$this->loggingTable = 'listmailerlogtable'; //this does not need to exist. if it does not it will be created.
		$this->pauseTime = 10; //seconds to pause between email blocks
		$this->numEmailsinBlock = 20; //number of emails to send per block
		$this->fromAddress = ''; //the email address that the mail should be sent from
		$this->fromName = '';//the name of the sender
		
		/*
		 * perform some internal checks
		 */
		if (!$this->checkLogging()){
			$this->createLoggingTable();
		}
	}
	
	/**
	 * method to set the html and non-html etc variables for the mail shot
	 * 
	 * @return void
	 * @param $subject string	- the subject of the email
	 * @param $text string -	the text body of the email
	 * @param $html string [optional] - formed html body of the email
	 */
	public function setMessageInfo($subject, $text, $html=null){
		$this->textBody 	= $text;
		$this->htmlBody 	= $html;
		$this->subject 		= $subject;
	}
	
	/**
	 * method to perform the mail shot
	 * 
	 * @return void
	 */
	public function sendToList(){
		if (empty($this->text)) die ('You must set at least a plain text message');
		if (empty($this->subject)) die ('You must set a subject for the message');
		
		//get email recipients
		$this->getRecipients();
		
		//get count of recipients
		$count = count($this->getRecipients);
		
		//get the phpmailer class
		require_once("class.phpmailer.php");
		
		//create an outer loop
		$i = 0;			
		
		//initialise the phpmailer
		$mail = new PHPMailer();
		//set some common variables
		$mail->From     = $this->fromAddress;
		$mail->FromName = $this->fromName;
		$mail->Host     = $this->smtpHost;
		$mail->Mailer   = "smtp";
		$mail->Subject 	= $this->subject;
		
		while ($i<$count){
			//reset the timeout counter
			set_time_limit(60 + $this->pauseTime);
			for ($c=0; $c < $this->numEmailsinBlock; $c++){
				if ($i >= $count) break;	
				list($pixel, $uid) = $this->getTrackingPixel($this->emailRecipients[$i][1]);
				if (empty($this->htmlBody)){
					$mail->Body    	= $this->textBody;
				} else {
					$mail->isHTML(true); //set to html
					$mail->Body = str_replace('{TRACK}', $pixel, $this->htmlBody);
					$mail->AltBody = $this->textBody;
				}
				$mail->Body = $this->htmlBody . $pixel; 
				$mail->AddAddress($this->emailRecipients[$i][1], $this->emailRecipients[$i][0]);
    			if($mail->Send()){
    				$this->log($uid, 'sent', $this->emailRecipients[$i][1] );
    			} else {
					$this->log($uid, 'error', $this->emailRecipients[$i][1] );
    			}
				echo "$i {$this->emailRecipients[$i][1]} <br/>";
				$i++;
			    // Clear all addresses and attachments for next loop
			    $mail->ClearAddresses();
			} //close the inner loop
			sleep($this->pauseTime);
		} //close the outer loop
		echo 'process complete.  See the log for details of errors etc';
	}
	
	/**
	 * method for logging the opening of an email
	 * 
	 * @return 
	 * @param $uid string	- the unique identifier logged in the email
	 * @param $event string - the event message
	 * @param $email string - the email address
	 */
	public function track($uid, $event, $email){
		$this->log($uid, $event);
		$this->deliverPixel();
	}
	
	/**
	 * method to create the logging table if it does not already exist
	 * 
	 * @return 
	 */
	private function createLoggingTable(){
		$sql = <<<HTML
CREATE TABLE
IF NOT EXISTS
{$this->loggingTable}
(
	logID int(11) NOT NULL AUTO_INCREMENT ,
	logEmail varchar(255) NOT NULL,
	logUniqueID varchar(255) NOT NULL,
	logEvent varchar (10) NOT NULL,
	logTime int(16) NOT NULL
)
PRIMARY KEY logID
HTML;
		echo $sql;
		mysql_query($sql) or die (mysql_error());
	}
	
	/**
	 * method to determine whether the logging table has already been created
	 * 
	 * @return 
	 */
	private function checkLogging(){
		if ($this->logging){
			$query = "show tables where name='{$this->loggingTable}'";
			$result = mysql_query($query);
			if (mysql_num_rows($result) === 1){
				return true;
			} else {
				return false;
			}
			
		}
	}
	
	/**
	 * method to obtain the html to embed the tracking pixel
	 * 
	 * @return void
	 */
	private function getTrackingPixel($email){
		if($this->logging){
			$uid = $better_token = md5(uniqid(rand(), true));
			$url = "[URL unfurl="true"]http://".[/URL] $_SERVER['SERVER_NAME']  . $_SERVER['REQUEST_URI'] . "?id=$uid&action=getImage&email=$email";
			$html =  <<<HTML
<img width="1px" height="1px" src="{$url}" alt="tracking"/>
HTML;
			return array($html, $uid);
		} else {
			return array('','');
		}
	}
	
	/**
	 * method to obtain all the recipients of the mailshot in an object property
	 * 
	 * @return 
	 */
	private function getRecipients(){
		$sql = "Select {$this->nameCol}, {$this->emailCol} from {$this->dbTable}";
		$results = mysql_query($sql) or die (mysql_error());
		//create holding variable
		$this->emailRecipients = array(); //
		while ($this->emailRecipients[] = mysql_fetch_array($result, MYSQL_NUM)){
			//do nothing
		}
	}
	
	/**
	 * method to log data
	 * 
	 * @return void
	 * @param $uniqueID string - the unique ID associated with the email recipient for this mailshot.
	 * @param $event string - text to be logged
	 * @param $emailAddress string - email address of recipient
	 */
	private function log($uniqueID, $event, $emailAddress){
		if ($this->logging){
			$params = array($emailAddress, $uniqueID, $event, time());
			$params = array_walk($params, 'mysql_real_escape_string');
			$sql = "insert into {$this->loggingTable} 
			(logID, logEmail, logUniqueID, logEvent, logTime) 
			VALUES
			(NULL, '%s', '%s', '%s', '%s');";
			mysql_query(vsprintf($sql, $params));
		}
	}
	
	/**
	 * method to deliver the actual pixel image so we don't get a broken image on the email.
	 * @return void
	 */
	private function deliverPixel(){
		if (!file_exists('pixel.png')){
			$this->createPixel();
		} 
		//send some no cacheing headers
		header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' );
		header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
		header( 'Cache-Control: no-store, no-cache, must-revalidate' );
		header( 'Cache-Control: post-check=0, pre-check=0', false );
		header( 'Pragma: no-cache' );
		header('Content-Length: '.filesize('pixel.png'));
        header('Content-Type: image/png');
		readfile('pixel.gif');
		exit();
	}
	
	/**
	 * method to create a transparent png pixel image if one has not already been created
	 * 
	 * @return void
	 */
	private function createPixel(){
		$pixel = imagecreatetruecolor(1, 1);
		imagesavealpha($pixel, true);
		$trans_colour = imagecolorallocatealpha($pixel, 0, 0, 0, 127);
		imagefill($pixel, 0, 0, $trans_colour);
		
		//now save the image
		imagepng($pixel, 'pixel.png');
	}
}
?>

all comments/fixes welcome in this thread.
 
Wow, thank you!

I'll test it out, debug, etc., and let you know.

Thanks!
-Kerry
 
Geez. That's huge. If you want something smaller, here...

Code:
#!/usr/bin/php -q
<?php
mysql_connect('server_ip','username','password');
@mysql_select_db('database') or die();

$sql = "select email from table";
$result = mysql_query($sql) or die('Query failed: ' . mysql_error());

$body = "Whatever the message text is";
$subject = "Some Subject";
$from = "whoever@someserver.org";
$headers  = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/html; charset=iso-8859-1; encoding=quoted-printable' . "\r\n";
$headers .= "From: $from";

while ($row = mysql_fetch_row($result)){
	mail($row[0],$subject,$body,$headers);
}
?>

While not as pretty as jpadie's, It should serve it's purpose.

Mark
 
I forgot the mysql_close(); at the end. Oh well...it'll still work.

Mark
 
Mark
the key differences between my script and a simple call to mail() are:

1. logging in a database table (including creating the table)
2. pixel tracking (including creating the pixel image on the fly and then cacheing it)
3. html multipart/alternative email (thanks to phpmailer)
4. batch sending to avoid smtp problems
5. phpdoc comments

i completely agree that you can do a rudimentary list manager in only a few lines, but the consistent question that we see in this forum is how to stop the smtp server from choking by injecting a delay. if you took the logging and tracking functions out of my code, it would be reasonably slimline too!

 
jpadie,
Believe me, I wasn't suggesting my code is better. I just figured that a newbie might read this and be intimidated.

Thought I'd offer an extremely simplistic answer to the question...

BTW, I'm also stealing your code for later. :)

Mark
 
sorry Mark, i didn't mean to imply that you were dissing my code! i was just pointing out the 'functionality' offered and that it wasn't quite as bloated as it might seem so that other readers might not be put off.

i'm quite sure there are bugs in it, so please holler if you find any.

 
I've found a couple, nothing major, and I'm just working out all the functionality, I'll get back with the code I use once it's fully up and working :)

I have changed a few of the settings... (for PHPMailer and so on) so those would probably have to be reset to a default.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top