I wrote this class. It works great! You can send just about as many attachments as you like and include HTML in the message. The only bug is that every email looks like there is an attachment. Hope this helps.
class Email {
// Public Variables
public $To = "";
public $Title = "";
public $Message = "";
public $From = "";
public $FromName = "";
public $ReplyTo = "";
public $ReplyToName = "";
public $ReturnPath = "";
public $ReturnPathName = "";
public $Headers = "";
private $Boundry = "";
private $Attachments = array();
private $FinalData = "";
private $EOL = "\r\n";
private $FinalHeaders = "";
/**
* Send - Send Message based on Populated Class Vars
*
* Will return false, and fail to send message, if required fields are empty.
*
* @access public
* @return bool True on Success, False on Failure
*/
public function Send() {
if ($this->To && $this->From) {
// Build Email
$this->BuildEmail();
// SEND IT!!!
return mail( $this->To, $this->Title, $this->FinalData, $this->FinalHeaders );
} else {
throw new Exception('"To" and "From" properties (email addresses) must be set before sending email');
}
}
/**
* AttachFile - Include file to be sent as an attachment
*
* @access public
* @param string $filename
* @param string $contents
* @return bool True on Success, False on Failure
*/
public function AttachFile( $filename, $filetype, $filedata ) {
$this->Attachments[] = new Attachment($filename, $filetype, $filedata);
}
/* -- Private Functions -- */
/**
* Put the email string all together
*
* @access private
*/
private function BuildEmail() {
// Set boundary
$this->Boundry = md5(uniqid());
// Build main headers
$this->BuildHeaders();
// Start first boundary
$this->FinalData .= "--".$this->Boundry.$this->EOL;
// Assemble message
$this->IncludeMessage();
// Assemble attachments
$this->IncludeAttachments();
}
/**
* IncludeMessage - Includes message into FinalData string
*
* @access private
*/
private function IncludeMessage() {
$this->FinalData .= "Content-Type: text/html; charset=\"iso-8859-1\"{$this->EOL}";
$this->FinalData .= "Content-Transfer-Encoding: 7bit".$this->EOL.$this->EOL;
$this->FinalData .= $this->Message.$this->EOL.$this->EOL;
$this->FinalData .= "--".$this->Boundry.$this->EOL;
}
/**
* IncludeAttachments - Include previously attachmented files into FinalData string
*
* This method should never be called explicitly, as it is called from within the
* `Send` function.
*
* @access private
*/
private function IncludeAttachments() {
foreach ($this->Attachments as $attachment) {
$this->FinalData .= "Content-Type: ".$attachment->filetype.$this->EOL;
$this->FinalData .= "Content-Transfer-Encoding: base64".$this->EOL;
$this->FinalData .= "Content-Disposition: attachment; filename=\"{$attachment->filename}\"".$this->EOL.$this->EOL;
$this->FinalData .= chunk_split(base64_encode($attachment->filedata));
$this->FinalData .= "--".$this->Boundry.$this->EOL;
}
}
/**
* BuildHeaders - Compile headers from member vars
*
* This method should never be called explicitly, as it is called from within the
* `Send` function.
*
* @access private
*/
private function BuildHeaders() {
$headers = "";
// From
if($this->FromName) $headers .= "From: ".$this->FromName." From.">".$this->EOL;
else $headers .= "From: {$this->From}{$this->EOL}";
// Reply-To
if(!$this->ReplyTo) $this->ReplyTo = $this->From;
if($this->ReplyToName) $headers .= "Reply-To: ".$this->ReplyToName." ReplyTo.">".$this->EOL;
else $headers .= "Reply-To: {$this->ReplyTo}{$this->EOL}";
// Return-Path
if(!$this->ReturnPath) $this->ReturnPath = $this->From;
if($this->ReturnPathName) $headers .= "Return-Path: ".$this->ReturnPathName." ReturnPath.">".$this->EOL;
else $headers .= "Return-Path: {$this->ReturnPath}{$this->EOL}";
// Message-ID
$headers .= "Message-ID: ".$this->EOL;
// X-Mailer ... dunno wut foh
$headers .= "X-Mailer: PHP v".phpversion().$this->EOL;
// MIME-Version
$headers .= "MIME-Version: 1.0{$this->EOL}";
// Content-Type, DO NOT CHANGE, must stay for attachments and whatnot
$headers .= "Content-Type: multipart/mixed; boundary=\"{$this->Boundry}\";{$this->EOL}";
// Append additional headers although there probably shouldn't ever be any
$this->FinalHeaders = $headers . $this->Headers;
}
}
class Attachment {
public $filename;
public $filetype;
public $filedata;
public function __construct($filename, $filetype, $filedata) {
$this->filename = $filename;
$this->filetype = $filetype;
$this->filedata = $filedata;
}
}