Monday 19 March 2012

My PEAR Net_SMTP function for PHP

OK, so some time ago I had an issue that I needed to send multipart/mime email through an authenticated SMTP server.  Had I been using a Linux distro this wouldn't have been a problem, as I could have simply added the authentication information into the relevant .ini files and that would have let the PHP mail()connect and send.  However I am normally coding for Windows environments so needed another solution.  I had a poke about on Google, as you do, and found that there were a fair few third party libraries that were out there, under differing license models, that would do the job.  Nothing was available as an inherent function in PHP.  Resigned that I was going to have to install something new, I opted for the PEAR NetSMTP class. This was because I already had the base components of PEAR installed on the system, so all I had to do was grab the package and its dependencies and away I could go.   And so started a three day fight to get the damn thing to send a mail.

What I found to be of particular detriment to my cause was that there was so little documentation for the class, and in particular its use, that it was a full on trial and error experience.  As a result I had to ask several questions on phpfreaks.com and, with some help on there I got the thing working as I needed it to.  Having spent as long as I did trying to make it all work as I wanted it to, I thought I would create a function for others to use to make life easier for those in a similar position.  So I wrote the following:

<?phprequire_once 'Net/SMTP.php'//stick this line somewhere at the top of your page
/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*
I wrote this function to use the PEAR Net_SMTP class as I needed something that
would pass SMTP authentication information, and didn't want to install any new
librarys.  The most important parts of this were getting the right line terminator
and then getting the right number of them for each line!
Feel free to tweek this as much as you like, just don't change any of the line
ends or your fixing it on your own :D
--This is NOT configured to work with SSL or TSL (so no sending through gmail)
Any questions you can get in touch at:
muddyfunster.webdev@gmail.com
*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/

 function sendSMTP($subject$body$user='defaultUserName'$pass='defaultPass'$to='Friendly Name'$destination='default@recipient.ext'$from='Friendly Name'$sender='default@address.ext'$fName=null$attachment=null){ 
//set defaults for user name, password, to, from, sender and recipient here ^^^
$e "\n"; //define end of line 
$bound"==MUDDY_FUNSTER_".md5(time()); //create a unique boundary for this mail to separate each different type in the message.
 @$smtp = new Net_SMTP("your.mailserver.ext"25); // set to youe mail providers A record and port number (IP Addresses will also work for server) 
@$smtp->connect(60); //create connection and set timeout duration 
@$smtp->helo('your_mail_domain.ext'); //start comunication with server --change to your mail providers domain    
@$smtp->auth($user$pass);  //authenticate account 
@$smtp->mailFrom("$sender");  //email address of authenticated account, can set default in function declaration
@$smtp->rcptTo("$destination");   //recipient of mail, can set default in function declaration 
$header "";  //set header as empty 
$header .= "From: $to <$sender>".$e// Set Friendly Name and address of sender
$header .= "To: $from <$destination>".$e// Set Friendly name and address of recipient
$header .= "Subject: $subject".$e;  //Set mail Subject 
$header .= "Reply-To: $sender".$e;  //Set Reply-to address 
$header .= 'MIME-Version:1.0'.$e;   //use MIME transport 
$header .= "Content-type:multipart/mixed;"// Define multipart mail contnent 
$header .= "boundary=\"".$bound."\"".$e.$e//set unique boundary for each different type of content 
$message $header//include headers into message information 
$message .= "--".$bound.$e//open boundary 
$message .= "Content-type:text/html;";  //set contnent as html for mail body
$message .= "charset=\"iso-8859-1\";".$e//set charactor set to be used in mail body - can be changed to suit 
$message .= "Content-disposition:inline;"//use inline to inferr displaying of contnet in the body without need for end user input 
$message .= "Content-transfer-encoding:quoted-printable".$e.$e.$e//set transfer encoding for html text content
$message .= $body.$e.$e//add the contnent of $body which is passed into the function
if($attachment != null && $fName != null){ //check if there is an attchment being passed into the function and that it has a name
$message .= "--".$bound.$e//add boundary to change to next content type
$message .= "Content-type:application/octet-stream;"//set content type to suitable type for attachment (octet-stream is for generic binary data other are available) 
$message .= "name=\"$fName.xml\"".$e//set the file name
 $message .= "Content-disposition:attachment;"//use attachment to infer data that is being passed as a file 
$message .= "filename=\"$fName.ext\";".$e//set the filename and extension as it will be recieved 
$message .= "Content-transfer-encoding:base64".$e.$e// encode the file for transfer
$message .= $attachment.$e.$e// add attachment contents 
} 
$message .= "--$bound--".$e//closing boundary shows it's the last part of the MIME and the mail is now complete 
@$smtp->data($message); //send message to the server 
$msg $smtp->getResponse(); // get server response array format -- $msg = Array([0]=>'server numeric code' [1]=>'Text message from server for code') -- hMailServer success response code is 250.  This can be called after any of the $smtp-> calls for error capture
@$smtp->disconnect(); // close server connection
 return $msg//pass out server response array
 }                     
 //call function using $var = sendSMTP($subject, $body, $user, $pass, $to, $recipientAddress, $from, $senderAddress, $filenameOfAttachment, $attachmentContent);
//$to and $from are the "Friendly Name" values for the message e.g. John Doe
//if you are passing in attachment content you MUST pass in a file name (prefferably with extension, but thats your targets problem) for it as well.

 ?>

The formatting has been a little upset posting the code up like this, so if you have any issues copying it you can find the same code at the end of my thread on phpfreaks.com here.

To use this function you must have PEAR Net_SMTP installed and up to date.  Once that's done just copy this code and save it in either a new .php file and load it using include_once or paste it into your existing include files/current page.

This function lets you send HTML formatted messages with or without an attachment.  The other thing is that it is written to pass in attachments on the fly, so there is no need to have an existing file saved on the server to attach (I wrote it this way as my original code was generating xml file attachments from a database lookup, so I really didn't want a bunch of files littering the server when I already had the information in the database anyway).

You will also see a whole bunch of @ suppressors in the function.  I normally avoid using these, but something in the way the Net_SMTP class accesses the PEAR error handling class keeps throwing warnings, even though there isn't an issue with the actual function or it's coding, it's just the relationship between the SMTP and PEAR error classes that's a bit out.

I have tested this using hMail free mail server and it worked a treat.  The last few lines of comments explain how to call the function in your code and how to read the server response array that the function returns.

Another thing is the function declaration has the option for default values, you will obviously need to change these if you want to use them.  I do feel that I should point out, this sends mail as a fully authorised account on whatever mail server you hook it up to, thus any spam sent from this will be traced to your mail server, not just the script, so you would probably want access controls in place if you choose to use all default values.

Enjoy, and let me know if you have any problems with this.

No comments:

Post a Comment