3 * Filename.......: class.html.mime.mail.inc
4 * Project........: HTML Mime mail class
5 * Last Modified..: $Date: 2007/06/19 15:29:18 $
6 * CVS Revision...: $Revision: 1.1 $
7 * Copyright......: 2001, 2002 Richard Heyes
10 require_once(dirname(__FILE__
) . '/mimePart.php');
15 * The html part of the message
21 * The text part of the message(only used in TEXT only messages)
27 * The main body of the message after building
33 * The alternative text to the HTML part (only used in HTML messages)
39 * An array of embedded images/objects
45 * An array of recognised image types for the findHtmlImages() method
51 * Parameters that affect the build process
57 * Array of attachments
63 * The main message headers
69 * Whether the message has been built or not
75 * The return path address. If not set the From:
76 * address is used instead
82 * Array of information needed for smtp sending
88 * Constructor function. Sets the headers
92 function htmlMimeMail()
95 * Initialise some variables.
97 $this->html_images
= array();
98 $this->headers
= array();
99 $this->is_built
= false;
102 * If you want the auto load functionality
103 * to find other image/file types, add the
104 * extension and content type here.
106 $this->image_types
= array(
107 'gif' => 'image/gif',
108 'jpg' => 'image/jpeg',
109 'jpeg' => 'image/jpeg',
110 'jpe' => 'image/jpeg',
111 'bmp' => 'image/bmp',
112 'png' => 'image/png',
113 'tif' => 'image/tiff',
114 'tiff' => 'image/tiff',
115 'swf' => 'application/x-shockwave-flash'
121 $this->build_params
['html_encoding'] = 'quoted-printable';
122 $this->build_params
['text_encoding'] = '7bit';
123 $this->build_params
['html_charset'] = 'UTF-8';
124 $this->build_params
['text_charset'] = 'UTF-8';
125 //$this->build_params['head_charset'] = 'ISO-8859-1';
126 $this->build_params
['head_charset'] = 'UTF-8';
127 $this->build_params
['text_wrap'] = 998;
130 * Defaults for smtp sending
132 if (!empty($GLOBALS['HTTP_SERVER_VARS']['HTTP_HOST'])) {
133 $helo = $GLOBALS['HTTP_SERVER_VARS']['HTTP_HOST'];
134 } elseif (!empty($GLOBALS['HTTP_SERVER_VARS']['SERVER_NAME'])) {
135 $helo = $GLOBALS['HTTP_SERVER_VARS']['SERVER_NAME'];
140 $this->smtp_params
['host'] = 'localhost';
141 $this->smtp_params
['port'] = 25;
142 $this->smtp_params
['helo'] = $helo;
143 $this->smtp_params
['auth'] = false;
144 $this->smtp_params
['user'] = '';
145 $this->smtp_params
['pass'] = '';
148 * Make sure the MIME version header is first.
150 $this->headers
['MIME-Version'] = '1.0';
154 * This function will read a file in
155 * from a supplied filename and return
156 * it. This can then be given as the first
157 * argument of the the functions
158 * add_html_image() or add_attachment().
160 function getFile($filename)
163 if ($fp = fopen($filename, 'rb')) {
165 $return .= fread($fp, 1024);
176 * Accessor to set the CRLF style
178 function setCrlf($crlf = "\n")
180 if (!defined('CRLF')) {
181 define('CRLF', $crlf, true);
184 if (!defined('MAIL_MIMEPART_CRLF')) {
185 define('MAIL_MIMEPART_CRLF', $crlf, true);
190 * Accessor to set the SMTP parameters
192 function setSMTPParams($host = null, $port = null, $helo = null, $auth = null, $user = null, $pass = null)
194 if (!is_null($host)) $this->smtp_params
['host'] = $host;
195 if (!is_null($port)) $this->smtp_params
['port'] = $port;
196 if (!is_null($helo)) $this->smtp_params
['helo'] = $helo;
197 if (!is_null($auth)) $this->smtp_params
['auth'] = $auth;
198 if (!is_null($user)) $this->smtp_params
['user'] = $user;
199 if (!is_null($pass)) $this->smtp_params
['pass'] = $pass;
203 * Accessor function to set the text encoding
205 function setTextEncoding($encoding = '7bit')
207 $this->build_params
['text_encoding'] = $encoding;
211 * Accessor function to set the HTML encoding
213 function setHtmlEncoding($encoding = 'quoted-printable')
215 $this->build_params
['html_encoding'] = $encoding;
219 * Accessor function to set the text charset
221 function setTextCharset($charset = 'ISO-8859-1')
223 $this->build_params
['text_charset'] = $charset;
227 * Accessor function to set the HTML charset
229 function setHtmlCharset($charset = 'ISO-8859-1')
231 $this->build_params
['html_charset'] = $charset;
235 * Accessor function to set the header encoding charset
237 function setHeadCharset($charset = 'ISO-8859-1')
239 $this->build_params
['head_charset'] = $charset;
243 * Accessor function to set the text wrap count
245 function setTextWrap($count = 998)
247 $this->build_params
['text_wrap'] = $count;
251 * Accessor to set a header
253 function setHeader($name, $value)
255 $this->headers
[$name] = $value;
259 * Accessor to add a Subject: header
261 function setSubject($subject)
263 $this->headers
['Subject'] = $subject;
267 * Accessor to add a From: header
269 function setFrom($from)
271 $this->headers
['From'] = $from;
275 * Accessor to set the return path
277 function setReturnPath($return_path)
279 $this->return_path
= $return_path;
283 * Accessor to add a Cc: header
287 $this->headers
['Cc'] = $cc;
291 * Accessor to add a Bcc: header
293 function setBcc($bcc)
295 $this->headers
['Bcc'] = $bcc;
299 * Adds plain text. Use this function
300 * when NOT sending html email
302 function setText($text = '')
308 * Adds a html part to the mail.
309 * Also replaces image names with
312 function setHtml($html, $text = null, $images_dir = null)
315 $this->html_text
= $text;
317 if (isset($images_dir)) {
318 $this->_findHtmlImages($images_dir);
323 * Function for extracting images from
324 * html source. This function will look
325 * through the html code supplied by add_html()
326 * and find any file that ends in one of the
327 * extensions defined in $obj->image_types.
328 * If the file exists it will read it in and
329 * embed it, (not an attachment).
333 function _findHtmlImages($images_dir)
335 // Build the list of image extensions
336 while (list($key,) = each($this->image_types
)) {
337 $extensions[] = $key;
340 preg_match_all('/(?:"|\')([^"\']+\.('.implode('|', $extensions).'))(?:"|\')/Ui', $this->html
, $images);
342 for ($i=0; $i<count($images[1]); $i++
) {
343 if (file_exists($images_dir . $images[1][$i])) {
344 $html_images[] = $images[1][$i];
345 $this->html
= str_replace($images[1][$i], basename($images[1][$i]), $this->html
);
349 if (!empty($html_images)) {
351 // If duplicate images are embedded, they may show up as attachments, so remove them.
352 $html_images = array_unique($html_images);
355 for ($i=0; $i<count($html_images); $i++
) {
356 if ($image = $this->getFile($images_dir.$html_images[$i])) {
357 $ext = substr($html_images[$i], strrpos($html_images[$i], '.') +
1);
358 $content_type = $this->image_types
[strtolower($ext)];
359 $this->addHtmlImage($image, basename($html_images[$i]), $content_type);
366 * Adds an image to the list of embedded
369 function addHtmlImage($file, $name = '', $c_type='application/octet-stream')
371 $this->html_images
[] = array(
375 'cid' => md5(uniqid(time()))
381 * Adds a file to the list of attachments.
383 function addAttachment($file, $name = '', $c_type='application/octet-stream', $encoding = 'base64')
385 $this->attachments
[] = array(
389 'encoding' => $encoding
394 * Adds a text subpart to a mime_part object
396 function &_addTextPart(&$obj, $text)
398 $params['content_type'] = 'text/plain';
399 $params['encoding'] = $this->build_params
['text_encoding'];
400 $params['charset'] = $this->build_params
['text_charset'];
401 if (is_object($obj)) {
402 return $obj->addSubpart($text, $params);
404 return new Mail_mimePart($text, $params);
409 * Adds a html subpart to a mime_part object
411 function &_addHtmlPart(&$obj)
413 $params['content_type'] = 'text/html';
414 $params['encoding'] = $this->build_params
['html_encoding'];
415 $params['charset'] = $this->build_params
['html_charset'];
416 if (is_object($obj)) {
417 return $obj->addSubpart($this->html
, $params);
419 return new Mail_mimePart($this->html
, $params);
424 * Starts a message with a mixed part
426 function &_addMixedPart()
428 $params['content_type'] = 'multipart/mixed';
429 return new Mail_mimePart('', $params);
433 * Adds an alternative part to a mime_part object
435 function &_addAlternativePart(&$obj)
437 $params['content_type'] = 'multipart/alternative';
438 if (is_object($obj)) {
439 return $obj->addSubpart('', $params);
441 return new Mail_mimePart('', $params);
446 * Adds a html subpart to a mime_part object
448 function &_addRelatedPart(&$obj)
450 $params['content_type'] = 'multipart/related';
451 if (is_object($obj)) {
452 return $obj->addSubpart('', $params);
454 return new Mail_mimePart('', $params);
459 * Adds an html image subpart to a mime_part object
461 function &_addHtmlImagePart(&$obj, $value)
463 $params['content_type'] = $value['c_type'];
464 $params['encoding'] = 'base64';
465 $params['disposition'] = 'inline';
466 $params['dfilename'] = $value['name'];
467 $params['cid'] = $value['cid'];
468 $obj->addSubpart($value['body'], $params);
472 * Adds an attachment subpart to a mime_part object
474 function &_addAttachmentPart(&$obj, $value)
476 $params['content_type'] = $value['c_type'];
477 $params['encoding'] = $value['encoding'];
478 $params['disposition'] = 'attachment';
479 $params['dfilename'] = $value['name'];
480 $obj->addSubpart($value['body'], $params);
484 * Builds the multipart message from the
485 * list ($this->_parts). $params is an
486 * array of parameters that shape the building
487 * of the message. Currently supported are:
489 * $params['html_encoding'] - The type of encoding to use on html. Valid options are
490 * "7bit", "quoted-printable" or "base64" (all without quotes).
491 * 7bit is EXPRESSLY NOT RECOMMENDED. Default is quoted-printable
492 * $params['text_encoding'] - The type of encoding to use on plain text Valid options are
493 * "7bit", "quoted-printable" or "base64" (all without quotes).
495 * $params['text_wrap'] - The character count at which to wrap 7bit encoded data.
496 * Default this is 998.
497 * $params['html_charset'] - The character set to use for a html section.
498 * Default is ISO-8859-1
499 * $params['text_charset'] - The character set to use for a text section.
500 * - Default is ISO-8859-1
501 * $params['head_charset'] - The character set to use for header encoding should it be needed.
502 * - Default is ISO-8859-1
504 function buildMessage($params = array())
506 if (!empty($params)) {
507 while (list($key, $value) = each($params)) {
508 $this->build_params
[$key] = $value;
512 if (!empty($this->html_images
)) {
513 foreach ($this->html_images
as $value) {
514 $this->html
= str_replace($value['name'], 'cid:'.$value['cid'], $this->html
);
519 $attachments = !empty($this->attachments
) ?
true : false;
520 $html_images = !empty($this->html_images
) ?
true : false;
521 $html = !empty($this->html
) ?
true : false;
522 $text = isset($this->text
) ?
true : false;
525 case $text AND !$attachments:
526 $message = &$this->_addTextPart($null, $this->text
);
529 case !$text AND $attachments AND !$html:
530 $message = &$this->_addMixedPart();
532 for ($i=0; $i<count($this->attachments
); $i++
) {
533 $this->_addAttachmentPart($message, $this->attachments
[$i]);
537 case $text AND $attachments:
538 $message = &$this->_addMixedPart();
539 $this->_addTextPart($message, $this->text
);
541 for ($i=0; $i<count($this->attachments
); $i++
) {
542 $this->_addAttachmentPart($message, $this->attachments
[$i]);
546 case $html AND !$attachments AND !$html_images:
547 if (!is_null($this->html_text
)) {
548 $message = &$this->_addAlternativePart($null);
549 $this->_addTextPart($message, $this->html_text
);
550 $this->_addHtmlPart($message);
552 $message = &$this->_addHtmlPart($null);
556 case $html AND !$attachments AND $html_images:
557 if (!is_null($this->html_text
)) {
558 $message = &$this->_addAlternativePart($null);
559 $this->_addTextPart($message, $this->html_text
);
560 $related = &$this->_addRelatedPart($message);
562 $message = &$this->_addRelatedPart($null);
563 $related = &$message;
565 $this->_addHtmlPart($related);
566 for ($i=0; $i<count($this->html_images
); $i++
) {
567 $this->_addHtmlImagePart($related, $this->html_images
[$i]);
571 case $html AND $attachments AND !$html_images:
572 $message = &$this->_addMixedPart();
573 if (!is_null($this->html_text
)) {
574 $alt = &$this->_addAlternativePart($message);
575 $this->_addTextPart($alt, $this->html_text
);
576 $this->_addHtmlPart($alt);
578 $this->_addHtmlPart($message);
580 for ($i=0; $i<count($this->attachments
); $i++
) {
581 $this->_addAttachmentPart($message, $this->attachments
[$i]);
585 case $html AND $attachments AND $html_images:
586 $message = &$this->_addMixedPart();
587 if (!is_null($this->html_text
)) {
588 $alt = &$this->_addAlternativePart($message);
589 $this->_addTextPart($alt, $this->html_text
);
590 $rel = &$this->_addRelatedPart($alt);
592 $rel = &$this->_addRelatedPart($message);
594 $this->_addHtmlPart($rel);
595 for ($i=0; $i<count($this->html_images
); $i++
) {
596 $this->_addHtmlImagePart($rel, $this->html_images
[$i]);
598 for ($i=0; $i<count($this->attachments
); $i++
) {
599 $this->_addAttachmentPart($message, $this->attachments
[$i]);
605 if (isset($message)) {
606 $output = $message->encode();
607 $this->output
= $output['body'];
608 $this->headers
= array_merge($this->headers
, $output['headers']);
610 // Add message ID header
611 srand((double)microtime()*10000000);
612 //$message_id = sprintf('<%s.%s@%s>', base_convert(time(), 10, 36), base_convert(rand(), 10, 36), !empty($GLOBALS['HTTP_SERVER_VARS']['HTTP_HOST']) ? $GLOBALS['HTTP_SERVER_VARS']['HTTP_HOST'] : $GLOBALS['HTTP_SERVER_VARS']['SERVER_NAME']);
613 // *** don't want to show atrium.ryzom.com in headers, so forcing to www.ryzom.com
614 $message_id = sprintf('<%s.%s@%s>', base_convert(time(), 10, 36), base_convert(rand(), 10, 36), 'www.ryzom.com');
615 $this->headers
['Message-ID'] = $message_id;
617 $this->is_built
= true;
625 * Function to encode a header if necessary
626 * according to RFC2047
628 function _encodeHeader($input, $charset = 'ISO-8859-1')
630 preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $input, $matches);
631 foreach ($matches[1] as $value) {
632 $replacement = preg_replace('/([\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value);
633 $input = str_replace($value, '=?' . $charset . '?Q?' . $replacement . '?=', $input);
642 * @param array $recipients
643 * @param string $type OPTIONAL
646 function send($recipients, $type = 'mail')
648 if (!defined('CRLF')) {
649 $this->setCrlf($type == 'mail' ?
"\n" : "\r\n");
652 if (!$this->is_built
) {
653 $this->buildMessage();
659 if (!empty($this->headers
['Subject'])) {
660 $subject = $this->_encodeHeader($this->headers
['Subject'], $this->build_params
['head_charset']);
661 unset($this->headers
['Subject']);
664 // Get flat representation of headers
665 foreach ($this->headers
as $name => $value) {
666 $headers[] = $name . ': ' . $this->_encodeHeader($value, $this->build_params
['head_charset']);
669 $to = $this->_encodeHeader(implode(', ', $recipients), $this->build_params
['head_charset']);
671 if (!empty($this->return_path
)) {
672 $result = mail($to, $subject, $this->output
, implode(CRLF
, $headers), '-f' . $this->return_path
);
674 $result = mail($to, $subject, $this->output
, implode(CRLF
, $headers));
677 // Reset the subject in case mail is resent
678 if ($subject !== '') {
679 $this->headers
['Subject'] = $subject;
687 require_once(dirname(__FILE__
) . '/smtp.php');
688 require_once(dirname(__FILE__
) . '/RFC822.php');
689 $smtp = &smtp
::connect($this->smtp_params
);
691 // Parse recipients argument for internet addresses
692 foreach ($recipients as $recipient) {
693 $addresses = Mail_RFC822
::parseAddressList($recipient, $this->smtp_params
['helo'], null, false);
694 foreach ($addresses as $address) {
695 $smtp_recipients[] = sprintf('%s@%s', $address->mailbox
, $address->host
);
698 unset($addresses); // These are reused
699 unset($address); // These are reused
701 // Get flat representation of headers, parsing
702 // Cc and Bcc as we go
703 foreach ($this->headers
as $name => $value) {
704 if ($name == 'Cc' OR $name == 'Bcc') {
705 $addresses = Mail_RFC822
::parseAddressList($value, $this->smtp_params
['helo'], null, false);
706 foreach ($addresses as $address) {
707 $smtp_recipients[] = sprintf('%s@%s', $address->mailbox
, $address->host
);
710 if ($name == 'Bcc') {
713 $headers[] = $name . ': ' . $this->_encodeHeader($value, $this->build_params
['head_charset']);
715 // Add To header based on $recipients argument
716 $headers[] = 'To: ' . $this->_encodeHeader(implode(', ', $recipients), $this->build_params
['head_charset']);
718 // Add headers to send_params
719 $send_params['headers'] = $headers;
720 $send_params['recipients'] = array_values(array_unique($smtp_recipients));
721 $send_params['body'] = $this->output
;
724 if (isset($this->return_path
)) {
725 $send_params['from'] = $this->return_path
;
726 } elseif (!empty($this->headers
['From'])) {
727 $from = Mail_RFC822
::parseAddressList($this->headers
['From']);
728 $send_params['from'] = sprintf('%s@%s', $from[0]->mailbox
, $from[0]->host
);
730 $send_params['from'] = 'postmaster@' . $this->smtp_params
['helo'];
734 if (!$smtp->send($send_params)) {
735 $this->errors
= $smtp->errors
;
744 * Use this method to return the email
745 * in message/rfc822 format. Useful for
746 * adding an email to another email as
747 * an attachment. there's a commented
748 * out example in example.php.
750 function getRFC822($recipients)
752 // Make up the date header as according to RFC822
753 $this->setHeader('Date', date('D, d M y H:i:s O'));
755 if (!defined('CRLF')) {
756 $this->setCrlf($type == 'mail' ?
"\n" : "\r\n");
759 if (!$this->is_built
) {
760 $this->buildMessage();
764 if (isset($this->return_path
)) {
765 $headers[] = 'Return-Path: ' . $this->return_path
;
768 // Get flat representation of headers
769 foreach ($this->headers
as $name => $value) {
770 $headers[] = $name . ': ' . $value;
772 $headers[] = 'To: ' . implode(', ', $recipients);
774 return implode(CRLF
, $headers) . CRLF
. CRLF
. $this->output
;