The class enables you to send emails with attachments, embedded images, html, or just plain-text via SMTP or using PHP's native mail function.
This is the constructor for the class, and it creates an email object.
$from | The email address of the sender. To include your name make it an array. The default is your servers configuration 'sendmail_from' value. |
$debug | Set to true if you're just testing the waters, and want to see what is going on. |
Example | $email = new Mailer (array('Yours Truly'=>'best@website.com'), true); |
Connects you to your SMTP server. Once you're in, you can send as many emails as you like without connecting over and over again. SMTP is much more reliable than mail(), and if this method returns true you can be confident that your email was sent and will be received. If you don't use this, or if you don't check to make sure that this method worked, then your email will be sent using PHP's native mail() function.
$server | Your outgoing (SMTP) server. The default is 'localhost'. |
$port | The port to connect to. The default is 25. |
$username | Your username. |
$password | Your password. |
Returns | True if successful, false if not. |
Example | if ($email->smtp('mail.yourwebsite.com', 25)) { // Proceed . . . |
This will include an attachment to your email, and you can call this method as many times as you like.
$filename | The name of the file. |
$filepath | The full server path to the attachments directory. Don't forget the trailing slash. |
Example | $email->attach ('report.pdf', '/base/directory/mysite.com/include/attachments/'); |
Just as advertised. When you include the directory to the images contained in your html, it will embed them in your email. Just keep calling this method for every email you want to send.
$to | The email address of the receiver. To include their name make it an array: $to['Their Name'] = 'receiver@email.com'; |
$subject | The subject of the email. |
$text | The body of your message. You don't need to worry about newlines ("\n\n") - it will take either newlines, or <br /> tags. |
$html | To display an html message. The $text string above is not needed if you declare this, but it is recommended for good form anyways. |
$images | The full server path to where the images in your email reside. Don't forget the trailing slash. |
Returns | True if successful, false if not. |
Example | $to = 'some@email.com'; $subject = 'Friendly Reminder'; $text = 'Tell your friends about me!'; $page = new Page ('Friendly Reminder'); $html = $page->display ('<img src="logo.gif" /><br />Tell your friends about me!'); unset ($page); $email->send($to, $subject, $text, $html, '/base/directory/mysite.com/include/images/'); |
This will close your open SMTP connection, and you should call this method after you $email->send() everything.
Example | $email->close(); |
Did some of your emails not get sent? Want to know what is going on so you can figure out what to do about it? This method will send you an informational array of all your interactions with SMTP, the expected responses in parentheses, and the actual response you were given.
Returns | An array of SMTP status codes. |
Example | trigger_error(serialize($email->debug()); |
<?php /* * author: Kyle Gadd * documentation: http://www.php-ease.com/classes/mailer.html * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ class Mailer { private $crlf = "\n"; private $from = ''; private $to = ''; private $subject = ''; private $text = ''; private $html = ''; private $headers = ''; private $mime_boundary = ''; private $html_images = array(); private $attachments = array(); private $smtp = array(); private $debug = false; function __construct ($from='', $debug='') { $this->smtp['connected'] = false; if (is_array($from)) { list($name, $address) = each($from); $this->from = $name . ' <' . $address . '>'; $this->smtp['from'] = $address; } else { if (empty($from)) $from = ini_get('sendmail_from'); $this->from = $from; $this->smtp['from'] = $from; } if ($debug === true) $this->debug = true; } public function smtp ($server='localhost', $port=25, $username='', $password='') { $this->crlf = "\r\n"; $this->smtp['fp'] = fsockopen($server, $port, $errno, $errstr, 30); if ($this->smtp['fp'] === false) { $this->smtp['log']['fsockopen'] = '(220) ' . $errno . ' - ' . $errstr; if ($this->debug) echo 'fsockopen ' . $this->smtp['log']['fsockopen'] . '<br /><br />'; } else { $this->log('connection', 220); fputs($this->smtp['fp'], "HELO {$_SERVER['REMOTE_ADDR']}" . $this->crlf); // or $_SERVER['HTTP_HOST'] ? if ($this->log('helo_response', 250)) { if (!empty($username)) { fputs($this->smtp['fp'], "AUTH LOGIN" . $this->crlf); if ($this->log('auth_login', 334)) { fputs($this->smtp['fp'], base64_encode($username) . $this->crlf); if ($this->log('auth_username', 334)) { fputs($this->smtp['fp'], base64_encode($password) . $this->crlf); if ($this->log('auth_password', 235)) { $this->smtp['connected'] = true; } // password } // username } // request } else { // if auth_login (334) 502 unimplemented you don't need a 'username' and 'password' $this->smtp['connected'] = true; } } // response } // handle if ($this->smtp['connected'] === false) $this->crlf = "\n"; // Back to the default return $this->smtp['connected']; } public function attach ($filename, $filepath) { $this->attachments[$filename] = $filepath; } public function send ($to, $subject, $text, $html='', $directory='') { $time = time(); $date = date('r', $time); if (is_array($to)) { list($name, $address) = each($to); $this->to = $name . ' <' . $address . '>'; $this->smtp['to'] = $address; } else { $this->to = $to; $this->smtp['to'] = $to; } $this->subject = $subject; $this->text = str_replace('<br />', $this->crlf, wordwrap(nl2br($text), 76, '<br />', true)); $this->html = $html; if (!empty($directory)) $this->images ($directory); $this->mime_boundary = sha1($date).rand(1000,9999); $this->headers['Date'] = $date; $this->headers['From'] = $this->from; $this->headers['Return-Path'] = '<' . $this->smtp['from'] . '>'; if ($this->smtp['connected']) { $this->headers['To'] = $this->to; $this->headers['Subject'] = $this->subject; } $result = $this->email_message(); $this->to = ''; $this->subject = ''; $this->text = ''; $this->html = ''; $this->headers = ''; $this->mime_boundary = ''; $this->html_images = array(); $this->attachments = array(); return $result; } public function close () { if ($this->smtp['connected']) { fputs($this->smtp['fp'], "QUIT" . $this->crlf); $result = $this->log('quit', 221); fclose($this->smtp['fp']); } } public function debug () { return $this->smtp['log']; } private function email_message () { if (empty($this->html) && empty($this->attachments)) { if ($this->debug) { echo '<pre>' . htmlspecialchars($this->headers() . $this->text) . '</pre><br /><br />'; } else { return $this->email($this->text); } } else { $this->headers['MIME-Version'] = '1.0'; $message = ''; if (!empty($this->attachments)) { $this->headers['Content-Type'] = 'mixed'; $message .= '--mixed-' . $this->mime_boundary . $this->crlf; } $message .= $this->insertText(); if (!empty($this->attachments)) { foreach ($this->attachments as $name => $path) { $message .= '--mixed-' . $this->mime_boundary . $this->crlf; $message .= $this->insertAttachment($name, $path); } $message .= '--mixed-' . $this->mime_boundary . '--' . $this->crlf . $this->crlf; } $message .= $this->crlf . '-- End --'; if ($this->debug) { echo '<pre>' . htmlspecialchars($this->headers() . $message) . '</pre><br /><br />'; } else { return $this->email($message); } } return false; } private function insertText () { $msgText = ''; if (!empty($this->html)) { if (empty($this->attachments)) { // because we set it to 'mixed', remember? $this->headers['Content-Type'] = 'alternative'; } else { $msgText .= 'Content-Type: multipart/alternative; boundary="alternative-' . $this->mime_boundary . '"' . $this->crlf . $this->crlf; } $msgText .= '--alternative-' . $this->mime_boundary . $this->crlf; } $msgText .= 'Content-Type: text/plain; charset=iso-8859-1' . $this->crlf; $msgText .= 'Content-Transfer-Encoding: 7bit' . $this->crlf . $this->crlf; $msgText .= $this->text . $this->crlf . $this->crlf; if (!empty($this->html)) { $msgText .= '--alternative-' . $this->mime_boundary . $this->crlf; $msgText .= $this->insertHtml(); $msgText .= '--alternative-' . $this->mime_boundary . '--' . $this->crlf . $this->crlf; } return $msgText; } private function insertHtml () { $msgHtml = ''; $images = !empty($this->html_images); if ($images) { foreach ($this->html_images as $name => $value) { $quoted = preg_quote($name); $cid = preg_quote($value['cid']); $this->html = preg_replace("#src=\"$quoted\"|src='$quoted'#", "src=\"cid:$cid\"", $this->html); $this->html = preg_replace("#background=\"$quoted\"|background='$quoted'#", "background=\"cid:$cid\"", $this->html); } $msgHtml .= 'Content-Type: multipart/related; boundary="related-' . $this->mime_boundary . '"' . $this->crlf . $this->crlf; $msgHtml .= '--related-' . $this->mime_boundary . $this->crlf; } $msgHtml .= 'Content-Type: text/html; charset=iso-8859-1' . $this->crlf; $msgHtml .= 'Content-Transfer-Encoding: quoted-printable' . $this->crlf . $this->crlf; $msgHtml .= $this->quotedPrintableEncode($this->html) . $this->crlf . $this->crlf; if ($images) { foreach ($this->html_images as $name => $value) { $msgHtml .= '--related-' . $this->mime_boundary . $this->crlf; $msgHtml .= 'Content-Type: ' . $value['type'] . $this->crlf; $msgHtml .= 'Content-Transfer-Encoding: base64' . $this->crlf; $msgHtml .= 'Content-Disposition: inline; filename="' . $name . '";' . $this->crlf; $msgHtml .= 'Content-ID: <' . $value['cid'] . '>' . $this->crlf . $this->crlf; $msgHtml .= $this->base64Encode($value['data']) . $this->crlf . $this->crlf; } $msgHtml .= '--related-' . $this->mime_boundary . '--' . $this->crlf . $this->crlf; } return $msgHtml; } private function quotedPrintableEncode($input, $line_max=76) { // for HTML $lines = preg_split("/\r?\n/", $input); $eol = $this->crlf; $escape = '='; $output = ''; while(list(, $line) = each($lines)) { $linlen = strlen($line); $newline = ''; for ($i=0; $i<$linlen; $i++) { $char = substr($line, $i, 1); $dec = ord($char); if (($dec == 32) AND ($i == ($linlen - 1))){ // convert space at eol only $char = '=20'; } elseif($dec == 9) { ; // Do nothing if a tab. } elseif(($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) { $char = $escape . strtoupper(sprintf('%02s', dechex($dec))); } if ((strlen($newline) + strlen($char)) >= $line_max) { // $eol is not counted $output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay $newline = ''; } $newline .= $char; } $output .= $newline . $eol; } $output = substr($output, 0, -1 * strlen($eol)); // Don't want last $eol return $output; } private function base64Encode ($input) { // for Attachments and Images return rtrim(chunk_split(base64_encode($input), 76, $this->crlf)); } private function images ($directory) { $image_types = array('jpg'=>'image/jpeg', 'gif'=>'image/gif', 'png'=>'image/png', 'swf'=>'application/x-shockwave-flash'); if (!empty($this->html)) { $extensions = array_keys($image_types); preg_match_all('/(?:"|\')([^"\']+\.('.implode('|', $extensions).'))(?:"|\')/Ui', $this->html, $matches); foreach ($matches[1] as $image) { if (file_exists($directory . $image)) { $html_images[] = $image; $this->html = str_replace($image, basename($image), $this->html); } } if (!empty($html_images)) { // If duplicate images are embedded, they may show up as attachments, so remove them. $html_images = array_unique($html_images); sort($html_images); foreach ($html_images as $img) { if ($image = file_get_contents($directory . $img)) { $ext = preg_replace('#^.*\.(\w{3,4})$#e', 'strtolower("$1")', $img); $name = basename($img); $type = $image_types[$ext]; $cid = '-' . str_replace('.'.$ext, '', $name) . '-' . $this->mime_boundary; $this->html_images[$name] = array('cid'=>$cid, 'data'=>$image, 'type'=>$type); } } } } } private function insertAttachment ($name, $path) { $attach = ''; $file = $path . $name; $handle = fopen($file, 'rb'); $data = fread($handle, filesize($file)); fclose($handle); $filetype = mime_content_type($file); $attach .= 'Content-Type: ' . $filetype . '; name="' . $name . '"' . $this->crlf; $attach .= 'Content-Transfer-Encoding: base64' . $this->crlf; $attach .= 'Content-Description: ' . $name . $this->crlf; $attach .= 'Content-Disposition: attachment; filename="' .$name. '"' . $this->crlf . $this->crlf; $attach .= $this->base64Encode($data) . $this->crlf . $this->crlf; return $attach; } private function headers () { foreach ($this->headers as $name => $value) { if ($name == 'Content-Type') { $headers[] = $name . ': multipart/' . $value . '; boundary="' . $value . '-' . $this->mime_boundary . '"'; $headers[] = 'Message-ID: <-' . $_SERVER['HTTP_HOST'] . '-' . $this->mime_boundary . '>'; } else { $headers[] = $name . ': ' . $value; } } return implode("\r\n", $headers) . "\r\n\r\n"; } private function email ($message) { $sent_email = false; if ($this->smtp['connected']) { fputs($this->smtp['fp'], "MAIL FROM: <{$this->smtp['from']}>" . $this->crlf); if ($this->log('mail_from_response', 250)) { fputs($this->smtp['fp'], "RCPT TO: <{$this->smtp['to']}>" . $this->crlf); if ($this->log('mail_' . $this->smtp['to'] . '_response', 250)) { fputs($this->smtp['fp'], "DATA" . $this->crlf); if ($this->log('data', 354)) { fputs($this->smtp['fp'], $this->headers() . $message . $this->crlf . '.' . $this->crlf); if ($this->log('message', 250)) { // implode($this->crlf, $email) $sent_email = true; } } } else { fputs($this->smtp['fp'], "RSET" . $this->crlf); $this->log('reset_mail', 250); } } } else { // not connected to smtp if (mail($this->to, $this->subject, $message, $this->headers())) { $sent_email = true; } } return $sent_email; } private function log ($desc, $code) { $response = fgets($this->smtp['fp'], 256); $this->smtp['log'][$desc] = $desc . ' (' . $code . ') ' . $response; if ($this->debug) echo $this->smtp['log'][$desc] . '<br /><br />'; if(substr($response,0,3) != $code) return false; return true; } } ?>