blob: abc77a54d7644ed73e02d4f4a3c68a50d40c2fd9 [file] [log] [blame]
adminb0dd10f2006-08-25 17:25:49 +00001<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * Code Igniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
8 * @author Rick Ellis
9 * @copyright Copyright (c) 2006, pMachine, Inc.
10 * @license http://www.codeignitor.com/user_guide/license.html
11 * @link http://www.codeigniter.com
12 * @since Version 1.0
13 * @filesource
14 */
15
16// ------------------------------------------------------------------------
17
18/**
19 * Code Igniter Email Class
20 *
21 * Permits email to be sent using Mail, Sendmail, or SMTP.
22 *
23 * @package CodeIgniter
24 * @subpackage Libraries
25 * @category Libraries
26 * @author Rick Ellis
27 * @link http://www.codeigniter.com/user_guide/libraries/email.html
28 */
29class CI_Email {
30
31 var $useragent = "Code Igniter";
32 var $mailpath = "/usr/sbin/sendmail"; // Sendmail path
33 var $protocol = "mail"; // mail/sendmail/smtp
34 var $smtp_host = ""; // SMTP Server. Example: mail.earthlink.net
35 var $smtp_user = ""; // SMTP Username
36 var $smtp_pass = ""; // SMTP Password
37 var $smtp_port = "25"; // SMTP Port
38 var $smtp_timeout = 5; // SMTP Timeout in seconds
39 var $wordwrap = TRUE; // true/false Turns word-wrap on/off
40 var $wrapchars = "76"; // Number of characters to wrap at.
41 var $mailtype = "text"; // text/html Defines email formatting
42 var $charset = "utf-8"; // Default char set: iso-8859-1 or us-ascii
43 var $multipart = "mixed"; // "mixed" (in the body) or "related" (separate)
44 var $alt_message = ''; // Alternative message for HTML emails
45 var $validate = FALSE; // true/false. Enables email validation
46 var $priority = "3"; // Default priority (1 - 5)
47 var $newline = "\n"; // Default newline. "\r\n" or "\n" (Use "\r\n" to comply with RFC 822)
48 var $bcc_batch_mode = FALSE; // true/false Turns on/off Bcc batch feature
49 var $bcc_batch_size = 200; // If bcc_batch_mode = true, sets max number of Bccs in each batch
50 var $_subject = "";
51 var $_body = "";
52 var $_finalbody = "";
53 var $_alt_boundary = "";
54 var $_atc_boundary = "";
55 var $_header_str = "";
56 var $_smtp_connect = "";
57 var $_encoding = "8bit";
58 var $_safe_mode = FALSE;
59 var $_IP = FALSE;
60 var $_smtp_auth = FALSE;
61 var $_replyto_flag = FALSE;
62 var $_debug_msg = array();
63 var $_recipients = array();
64 var $_cc_array = array();
65 var $_bcc_array = array();
66 var $_headers = array();
67 var $_attach_name = array();
68 var $_attach_type = array();
69 var $_attach_disp = array();
70 var $_protocols = array('mail', 'sendmail', 'smtp');
71 var $_base_charsets = array('iso-8859-1', 'us-ascii');
72 var $_bit_depths = array('7bit', '8bit');
73 var $_priorities = array('1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)');
74
75
76 /**
77 * Constructor - Sets Email Preferences
78 *
79 * The constructor can be passed an array of config values
80 */
81 function CI_Email($config = array())
82 {
83 if (count($config) > 0)
84 {
85 $this->initialize($config);
86 }
87
88 log_message('debug', "Email Class Initialized");
89 }
90 // END CI_Email()
91
92 // --------------------------------------------------------------------
93
94 /**
95 * Initialize preferences
96 *
97 * @access public
98 * @param array
99 * @return void
100 */
101 function initialize($config = array())
102 {
103 $this->clear();
104 foreach ($config as $key => $val)
105 {
106 if (isset($this->$key))
107 {
108 $method = 'set_'.$key;
109
110 if (method_exists($this, $method))
111 {
112 $this->$method($val);
113 }
114 else
115 {
116 $this->$key = $val;
117 }
118 }
119 }
120 $this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE;
121 $this->_safe_mode = (@ini_get("safe_mode") == 0) ? FALSE : TRUE;
122 }
123 // END initialize()
124
125 // --------------------------------------------------------------------
126
127 /**
128 * Initialize the Email Data
129 *
130 * @access public
131 * @return void
132 */
133 function clear()
134 {
135 $this->_subject = "";
136 $this->_body = "";
137 $this->_finalbody = "";
138 $this->_header_str = "";
139 $this->_replyto_flag = FALSE;
140 $this->_recipients = array();
141 $this->_headers = array();
142 $this->_debug_msg = array();
143
144 $this->_set_header('User-Agent', $this->useragent);
145 $this->_set_header('Date', $this->_set_date());
146 }
147 // END clear()
148
149 // --------------------------------------------------------------------
150
151 /**
152 * Set FROM
153 *
154 * @access public
155 * @param string
156 * @param string
157 * @return void
158 */
159 function from($from, $name = '')
160 {
161 if (preg_match( '/\<(.*)\>/', $from, $match))
162 $from = $match['1'];
163
164 if ($this->validate)
165 $this->validate_email($this->_str_to_array($from));
166
167 if ($name != '' && substr($name, 0, 1) != '"')
168 {
169 $name = '"'.$name.'"';
170 }
171
172 $this->_set_header('From', $name.' <'.$from.'>');
173 $this->_set_header('Return-Path', '<'.$from.'>');
174 }
175 // END from()
176
177 // --------------------------------------------------------------------
178
179 /**
180 * Set Reply-to
181 *
182 * @access public
183 * @param string
184 * @param string
185 * @return void
186 */
187 function reply_to($replyto, $name = '')
188 {
189 if (preg_match( '/\<(.*)\>/', $replyto, $match))
190 $replyto = $match['1'];
191
192 if ($this->validate)
193 $this->validate_email($this->_str_to_array($replyto));
194
195 if ($name == '')
196 {
197 $name = $replyto;
198 }
199
200 if (substr($name, 0, 1) != '"')
201 {
202 $name = '"'.$name.'"';
203 }
204
205 $this->_set_header('Reply-To', $name.' <'.$replyto.'>');
206 $this->_replyto_flag = TRUE;
207 }
208 // END reply_to()
209
210 // --------------------------------------------------------------------
211
212 /**
213 * Set Recipients
214 *
215 * @access public
216 * @param string
217 * @return void
218 */
219 function to($to)
220 {
221 $to = $this->_str_to_array($to);
222 $to = $this->clean_email($to);
223
224 if ($this->validate)
225 $this->validate_email($to);
226
227 if ($this->_get_protocol() != 'mail')
228 $this->_set_header('To', implode(", ", $to));
229
230 switch ($this->_get_protocol())
231 {
232 case 'smtp' : $this->_recipients = $to;
233 break;
234 case 'sendmail' : $this->_recipients = implode(", ", $to);
235 break;
236 case 'mail' : $this->_recipients = implode(", ", $to);
237 break;
238 }
239 }
240 // END to()
241
242 // --------------------------------------------------------------------
243
244 /**
245 * Set CC
246 *
247 * @access public
248 * @param string
249 * @return void
250 */
251 function cc($cc)
252 {
253 $cc = $this->_str_to_array($cc);
254 $cc = $this->clean_email($cc);
255
256 if ($this->validate)
257 $this->validate_email($cc);
258
259 $this->_set_header('Cc', implode(", ", $cc));
260
261 if ($this->_get_protocol() == "smtp")
262 $this->_cc_array = $cc;
263 }
264 // END cc()
265
266 // --------------------------------------------------------------------
267
268 /**
269 * Set BCC
270 *
271 * @access public
272 * @param string
273 * @param string
274 * @return void
275 */
276 function bcc($bcc, $limit = '')
277 {
admin1cf89aa2006-09-03 18:24:39 +0000278 if ($limit != '' && is_numeric($limit))
adminb0dd10f2006-08-25 17:25:49 +0000279 {
280 $this->bcc_batch_mode = true;
281 $this->bcc_batch_size = $limit;
282 }
283
284 $bcc = $this->_str_to_array($bcc);
285 $bcc = $this->clean_email($bcc);
286
287 if ($this->validate)
288 $this->validate_email($bcc);
289
290 if (($this->_get_protocol() == "smtp") OR ($this->bcc_batch_mode && count($bcc) > $this->bcc_batch_size))
291 $this->_bcc_array = $bcc;
292 else
293 $this->_set_header('Bcc', implode(", ", $bcc));
294 }
295 // END bcc()
296
297 // --------------------------------------------------------------------
298
299 /**
300 * Set Email Subject
301 *
302 * @access public
303 * @param string
304 * @return void
305 */
306 function subject($subject)
307 {
308 $subject = preg_replace("/(\r\n)|(\r)|(\n)/", "", $subject);
309 $subject = preg_replace("/(\t)/", " ", $subject);
310
311 $this->_set_header('Subject', trim($subject));
312 }
313 // END subject()
314
315 // --------------------------------------------------------------------
316
317 /**
318 * Set Body
319 *
320 * @access public
321 * @param string
322 * @return void
323 */
324 function message($body)
325 {
326 $body = rtrim(str_replace("\r", "", $body));
327
328 if ($this->wordwrap === TRUE AND $this->mailtype != 'html')
329 $this->_body = $this->word_wrap($body);
330 else
331 $this->_body = $body;
332
333 $this->_body = stripslashes($this->_body);
334 }
335 // END message()
336
337 // --------------------------------------------------------------------
338
339 /**
340 * Assign file attachments
341 *
342 * @access public
343 * @param string
344 * @return string
345 */
346 function attach($filename, $disposition = 'attachment')
347 {
348 $this->_attach_name[] = $filename;
349 $this->_attach_type[] = $this->_mime_types(next(explode('.', basename($filename))));
350 $this->_attach_disp[] = $disposition; // Can also be 'inline' Not sure if it matters
351 }
352 // END attach()
353
354 // --------------------------------------------------------------------
355
356 /**
357 * Add a Header Item
358 *
359 * @access public
360 * @param string
361 * @param string
362 * @return void
363 */
364 function _set_header($header, $value)
365 {
366 $this->_headers[$header] = $value;
367 }
368 // END _set_header()
369
370 // --------------------------------------------------------------------
371
372 /**
373 * Convert a String to an Array
374 *
375 * @access public
376 * @param string
377 * @return array
378 */
379 function _str_to_array($email)
380 {
381 if ( ! is_array($email))
382 {
383 if (ereg(',$', $email))
384 $email = substr($email, 0, -1);
385
386 if (ereg('^,', $email))
387 $email = substr($email, 1);
388
389 if (ereg(',', $email))
390 {
391 $x = explode(',', $email);
392 $email = array();
393
394 for ($i = 0; $i < count($x); $i ++)
395 $email[] = trim($x[$i]);
396 }
397 else
398 {
399 $email = trim($email);
400 settype($email, "array");
401 }
402 }
403 return $email;
404 }
405 // END _str_to_array()
406
407 // --------------------------------------------------------------------
408
409 /**
410 * Set Multipart Value
411 *
412 * @access public
413 * @param string
414 * @return void
415 */
416 function set_alt_message($str = '')
417 {
418 $this->alt_message = ($str == '') ? '' : $str;
419 }
420 // END set_alt_message()
421
422 // --------------------------------------------------------------------
423
424 /**
425 * Set Mailtype
426 *
427 * @access public
428 * @param string
429 * @return void
430 */
431 function set_mailtype($type = 'text')
432 {
433 $this->mailtype = ($type == 'html') ? 'html' : 'text';
434 }
435 // END set_mailtype()
436
437 // --------------------------------------------------------------------
438
439 /**
440 * Set Wordwrap
441 *
442 * @access public
443 * @param string
444 * @return void
445 */
446 function set_wordwrap($wordwrap = TRUE)
447 {
448 $this->wordwrap = ($wordwrap === FALSE) ? FALSE : TRUE;
449 }
450 // END set_wordwrap()
451
452 // --------------------------------------------------------------------
453
454 /**
455 * Set Protocal
456 *
457 * @access public
458 * @param string
459 * @return void
460 */
461 function set_protocol($protocol = 'mail')
462 {
463 $this->protocol = ( ! in_array($protocol, $this->_protocols)) ? 'mail' : strtolower($protocol);
464 }
465 // END set_protocol()
466
467 // --------------------------------------------------------------------
468
469 /**
470 * Set Priority
471 *
472 * @access public
473 * @param integer
474 * @return void
475 */
476 function set_priority($n = 3)
477 {
admin1cf89aa2006-09-03 18:24:39 +0000478 if ( ! is_numeric($n))
adminb0dd10f2006-08-25 17:25:49 +0000479 {
480 $this->priority = 3;
481 return;
482 }
483
484 if ($n < 1 OR $n > 5)
485 {
486 $this->priority = 3;
487 return;
488 }
489
490 $this->priority = $n;
491 }
492 // END set_priority()
493
494 // --------------------------------------------------------------------
495
496 /**
497 * Set Newline Character
498 *
499 * @access public
500 * @param string
501 * @return void
502 */
503 function set_newline($newline = "\n")
504 {
505 if ($newline != "\n" OR $newline != "\r\n" OR $newline != "\r")
506 {
507 $this->newline = "\n";
508 return;
509 }
510
511 $this->newline = $newline;
512 }
513 // END set_newline()
514
515 // --------------------------------------------------------------------
516
517 /**
518 * Set Message Boundry
519 *
520 * @access private
521 * @return void
522 */
523 function _set_boundaries()
524 {
525 $this->_alt_boundary = "B_ALT_".uniqid(''); // mulipart/alternative
526 $this->_atc_boundary = "B_ATC_".uniqid(''); // attachment boundary
527 }
528 // END _set_boundaries()
529
530 // --------------------------------------------------------------------
531
532 /**
533 * Get the Message ID
534 *
535 * @access private
536 * @return string
537 */
538 function _get_message_id()
539 {
540 $from = $this->_headers['Return-Path'];
541 $from = str_replace(">", "", $from);
542 $from = str_replace("<", "", $from);
543
544 return "<".uniqid('').strstr($from, '@').">";
545 }
546 // END _get_message_id()
547
548 // --------------------------------------------------------------------
549
550 /**
551 * Get Mail Protocol
552 *
553 * @access private
554 * @param bool
555 * @return string
556 */
557 function _get_protocol($return = true)
558 {
559 $this->protocol = strtolower($this->protocol);
560 $this->protocol = ( ! in_array($this->protocol, $this->_protocols)) ? 'mail' : $this->protocol;
561
562 if ($return == true)
563 return $this->protocol;
564 }
565 // END _get_protocol()
566
567 // --------------------------------------------------------------------
568
569 /**
570 * Get Mail Encoding
571 *
572 * @access private
573 * @param bool
574 * @return string
575 */
576 function _get_encoding($return = true)
577 {
578 $this->_encoding = ( ! in_array($this->_encoding, $this->_bit_depths)) ? '7bit' : $this->_encoding;
579
580 if ( ! in_array($this->charset, $this->_base_charsets))
581 $this->_encoding = "8bit";
582
583 if ($return == true)
584 return $this->_encoding;
585 }
586 // END _get_encoding()
587
588 // --------------------------------------------------------------------
589
590 /**
591 * Get content type (text/html/attachment)
592 *
593 * @access private
594 * @return string
595 */
596 function _get_content_type()
597 {
598 if ($this->mailtype == 'html' && count($this->_attach_name) == 0)
599 return 'html';
600
601 elseif ($this->mailtype == 'html' && count($this->_attach_name) > 0)
602 return 'html-attach';
603
604 elseif ($this->mailtype == 'text' && count($this->_attach_name) > 0)
605 return 'plain-attach';
606
607 else return 'plain';
608 }
609 // END _get_content_type()
610
611 // --------------------------------------------------------------------
612
613 /**
614 * Set RFC 822 Date
615 *
616 * @access public
617 * @return string
618 */
619 function _set_date()
620 {
621 $timezone = date("Z");
622 $operator = (substr($timezone, 0, 1) == '-') ? '-' : '+';
623 $timezone = abs($timezone);
624 $timezone = ($timezone/3600) * 100 + ($timezone % 3600) /60;
625
626 return sprintf("%s %s%04d", date("D, j M Y H:i:s"), $operator, $timezone);
627 }
628 // END _set_date()
629
630 // --------------------------------------------------------------------
631
632 /**
633 * Mime message
634 *
635 * @access private
636 * @return string
637 */
638 function _get_mime_message()
639 {
640 return "This is a multi-part message in MIME format.".$this->newline."Your email application may not support this format.";
641 }
642 // END _get_mime_message()
643
644 // --------------------------------------------------------------------
645
646 /**
647 * Validate Email Address
648 *
649 * @access public
650 * @param string
651 * @return bool
652 */
653 function validate_email($email)
654 {
655 if ( ! is_array($email))
656 {
657 $this->_set_error_message('email_must_be_array');
658 return FALSE;
659 }
660
661 foreach ($email as $val)
662 {
663 if ( ! $this->valid_email($val))
664 {
665 $this->_set_error_message('email_invalid_address', $val);
666 return FALSE;
667 }
668 }
669 }
670 // END validate_email()
671
672 // --------------------------------------------------------------------
673
674 /**
675 * Email Validation
676 *
677 * @access public
678 * @param string
679 * @return bool
680 */
681 function valid_email($address)
682 {
683 if ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $address))
684 return FALSE;
685 else
686 return TRUE;
687 }
688 // END valid_email()
689
690 // --------------------------------------------------------------------
691
692 /**
693 * Clean Extended Email Address: Joe Smith <joe@smith.com>
694 *
695 * @access public
696 * @param string
697 * @return string
698 */
699 function clean_email($email)
700 {
701 if ( ! is_array($email))
702 {
703 if (preg_match('/\<(.*)\>/', $email, $match))
704 return $match['1'];
705 else
706 return $email;
707 }
708
709 $clean_email = array();
710
711 for ($i=0; $i < count($email); $i++)
712 {
713 if (preg_match( '/\<(.*)\>/', $email[$i], $match))
714 $clean_email[] = $match['1'];
715 else
716 $clean_email[] = $email[$i];
717 }
718
719 return $clean_email;
720 }
721 // END clean_email()
722
723 // --------------------------------------------------------------------
724
725 /**
726 * Build alternative plain text message
727 *
728 * This function provides the raw message for use
729 * in plain-text headers of HTML-formatted emails.
730 * If the user hasn't specified his own alternative message
731 * it creates one by stripping the HTML
732 *
733 * @access private
734 * @return string
735 */
736 function _get_alt_message()
737 {
738 if (eregi( '\<body(.*)\</body\>', $this->_body, $match))
739 {
740 $body = $match['1'];
741 $body = substr($body, strpos($body, ">") + 1);
742 }
743 else
744 {
745 $body = $this->_body;
746 }
747
748 $body = trim(strip_tags($body));
749 $body = preg_replace( '#<!--(.*)--\>#', "", $body);
750 $body = str_replace("\t", "", $body);
751
752 for ($i = 20; $i >= 3; $i--)
753 {
754 $n = "";
755
756 for ($x = 1; $x <= $i; $x ++)
757 $n .= "\n";
758
759 $body = str_replace($n, "\n\n", $body);
760 }
761
762 return $this->word_wrap($body, '76');
763 }
764 // END _get_alt_message()
765
766 // --------------------------------------------------------------------
767
768 /**
769 * Word Wrap
770 *
771 * @access public
772 * @param string
773 * @param integer
774 * @return string
775 */
776 function word_wrap($str, $chars = '')
777 {
778 if ($chars == '')
779 $chars = ($this->wrapchars == "") ? "76" : $this->wrapchars;
780
781 $lines = split("\n", $str);
782
783 $output = "";
784
785 while (list(, $thisline) = each($lines))
786 {
787 if (strlen($thisline) > $chars)
788 {
789 $line = "";
790
791 $words = split(" ", $thisline);
792
793 while(list(, $thisword) = each($words))
794 {
795 while((strlen($thisword)) > $chars)
796 {
797 if (stristr($thisword, '{unwrap}') !== FALSE OR stristr($thisword, '{/unwrap}') !== FALSE)
798 {
799 break;
800 }
801
802 $cur_pos = 0;
803
804 for($i=0; $i < $chars - 1; $i++)
805 {
806 $output .= $thisword[$i];
807 $cur_pos++;
808 }
809
810 $output .= "\n";
811
812 $thisword = substr($thisword, $cur_pos, (strlen($thisword) - $cur_pos));
813 }
814
815 if ((strlen($line) + strlen($thisword)) > $chars)
816 {
817 $output .= $line."\n";
818
819 $line = $thisword." ";
820 }
821 else
822 {
823 $line .= $thisword." ";
824 }
825 }
826
827 $output .= $line."\n";
828 }
829 else
830 {
831 $output .= $thisline."\n";
832 }
833 }
834
835 return $output;
836 }
837 // END word_wrap()
838
839 // --------------------------------------------------------------------
840
841 /**
842 * Build final headers
843 *
844 * @access public
845 * @param string
846 * @return string
847 */
848 function _build_headers()
849 {
850 $this->_set_header('X-Sender', $this->clean_email($this->_headers['From']));
851 $this->_set_header('X-Mailer', $this->useragent);
852 $this->_set_header('X-Priority', $this->_priorities[$this->priority - 1]);
853 $this->_set_header('Message-ID', $this->_get_message_id());
854 $this->_set_header('Mime-Version', '1.0');
855 }
856 // END _build_headers()
857
858 // --------------------------------------------------------------------
859
860 /**
861 * Write Headers as a string
862 *
863 * @access public
864 * @return void
865 */
866 function _write_headers()
867 {
868 if ($this->protocol == 'mail')
869 {
870 $this->_subject = $this->_headers['Subject'];
871 unset($this->_headers['Subject']);
872 }
873
874 reset($this->_headers);
875 $this->_header_str = "";
876
877 foreach($this->_headers as $key => $val)
878 {
879 $val = trim($val);
880
881 if ($val != "")
882 {
883 $this->_header_str .= $key.": ".$val.$this->newline;
884 }
885 }
886
887 if ($this->_get_protocol() == 'mail')
888 $this->_header_str = substr($this->_header_str, 0, -1);
889 }
890 // END _write_headers()
891
892 // --------------------------------------------------------------------
893
894 /**
895 * Build Final Body and attachments
896 *
897 * @access public
898 * @return void
899 */
900 function _build_message()
901 {
902 $this->_set_boundaries();
903 $this->_write_headers();
904
905 $hdr = ($this->_get_protocol() == 'mail') ? $this->newline : '';
906
907 switch ($this->_get_content_type())
908 {
909 case 'plain' :
910
911 $hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
912 $hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding();
913
914 if ($this->_get_protocol() == 'mail')
915 {
916 $this->_header_str .= $hdr;
917 $this->_finalbody = $this->_body;
918
919 return;
920 }
921
922 $hdr .= $this->newline . $this->newline . $this->_body;
923
924 $this->_finalbody = $hdr;
925 return;
926
927 break;
928 case 'html' :
929
930 $hdr .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline;
931 $hdr .= $this->_get_mime_message() . $this->newline . $this->newline;
932 $hdr .= "--" . $this->_alt_boundary . $this->newline;
933
934 $hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
935 $hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline;
936 $hdr .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline;
937
938 $hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;
939 $hdr .= "Content-Transfer-Encoding: quoted/printable";
940
941 if ($this->_get_protocol() == 'mail')
942 {
943 $this->_header_str .= $hdr;
944 $this->_finalbody = $this->_body . $this->newline . $this->newline . "--" . $this->_alt_boundary . "--";
945
946 return;
947 }
948
949 $hdr .= $this->newline . $this->newline;
950 $hdr .= $this->_body . $this->newline . $this->newline . "--" . $this->_alt_boundary . "--";
951
952 $this->_finalbody = $hdr;
953 return;
954
955 break;
956 case 'plain-attach' :
957
958 $hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline;
959 $hdr .= $this->_get_mime_message() . $this->newline . $this->newline;
960 $hdr .= "--" . $this->_atc_boundary . $this->newline;
961
962 $hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
963 $hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding();
964
965 if ($this->_get_protocol() == 'mail')
966 {
967 $this->_header_str .= $hdr;
968
969 $body = $this->_body . $this->newline . $this->newline;
970 }
971
972 $hdr .= $this->newline . $this->newline;
973 $hdr .= $this->_body . $this->newline . $this->newline;
974
975 break;
976 case 'html-attach' :
977
978 $hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline;
979 $hdr .= $this->_get_mime_message() . $this->newline . $this->newline;
980 $hdr .= "--" . $this->_atc_boundary . $this->newline;
981
982 $hdr .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline .$this->newline;
983 $hdr .= "--" . $this->_alt_boundary . $this->newline;
984
985 $hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
986 $hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline;
987 $hdr .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline;
988
989 $hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;
990 $hdr .= "Content-Transfer-Encoding: quoted/printable";
991
992 if ($this->_get_protocol() == 'mail')
993 {
994 $this->_header_str .= $hdr;
995
996 $body = $this->_body . $this->newline . $this->newline;
997 $body .= "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline;
998 }
999
1000 $hdr .= $this->newline . $this->newline;
1001 $hdr .= $this->_body . $this->newline . $this->newline;
1002 $hdr .= "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline;
1003
1004 break;
1005 }
1006
1007 $attachment = array();
1008
1009 $z = 0;
1010
1011 for ($i=0; $i < count($this->_attach_name); $i++)
1012 {
1013 $filename = $this->_attach_name[$i];
1014 $basename = basename($filename);
1015 $ctype = $this->_attach_type[$i];
1016
1017 if ( ! file_exists($filename))
1018 {
1019 $this->_set_error_message('email_attachment_missing', $filename);
1020 return FALSE;
1021 }
1022
1023 $h = "--".$this->_atc_boundary.$this->newline;
1024 $h .= "Content-type: ".$ctype."; ";
1025 $h .= "name=\"".$basename."\"".$this->newline;
1026 $h .= "Content-Disposition: ".$this->_attach_disp[$i].";".$this->newline;
1027 $h .= "Content-Transfer-Encoding: base64".$this->newline;
1028
1029 $attachment[$z++] = $h;
1030 $file = filesize($filename) +1;
1031
1032 if ( ! $fp = fopen($filename, 'r'))
1033 {
1034 $this->_set_error_message('email_attachment_unredable', $filename);
1035 return FALSE;
1036 }
1037
1038 $attachment[$z++] = chunk_split(base64_encode(fread($fp, $file)));
1039 fclose($fp);
1040 }
1041
1042 if ($this->_get_protocol() == 'mail')
1043 {
1044 $this->_finalbody = $body . implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--";
1045
1046 return;
1047 }
1048
1049 $this->_finalbody = $hdr.implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--";
1050
1051 return;
1052 }
1053 // END _build_message()
1054
1055 // --------------------------------------------------------------------
1056
1057 /**
1058 * Send Email
1059 *
1060 * @access public
1061 * @return bool
1062 */
1063 function send()
1064 {
1065 if ($this->_replyto_flag == FALSE)
1066 {
1067 $this->reply_to($this->_headers['From']);
1068 }
1069
1070 if (( ! isset($this->_recipients) AND ! isset($this->_headers['To'])) AND
1071 ( ! isset($this->_bcc_array) AND ! isset($this->_headers['Bcc'])) AND
1072 ( ! isset($this->_headers['Cc'])))
1073 {
1074 $this->_set_error_message('email_no_recipients');
1075 return FALSE;
1076 }
1077
1078 $this->_build_headers();
1079
1080 if ($this->bcc_batch_mode AND count($this->_bcc_array) > 0)
1081 {
1082 if (count($this->_bcc_array) > $this->bcc_batch_size)
1083 return $this->batch_bcc_send();
1084 }
1085
1086 $this->_build_message();
1087
1088 if ( ! $this->_spool_email())
1089 return FALSE;
1090 else
1091 return TRUE;
1092 }
1093 // END send()
1094
1095 // --------------------------------------------------------------------
1096
1097 /**
1098 * Batch Bcc Send. Sends groups of Bccs in batches
1099 *
1100 * @access public
1101 * @return bool
1102 */
1103 function batch_bcc_send()
1104 {
1105 $float = $this->bcc_batch_size -1;
1106
1107 $flag = 0;
1108 $set = "";
1109
1110 $chunk = array();
1111
1112 for ($i = 0; $i < count($this->_bcc_array); $i++)
1113 {
1114 if (isset($this->_bcc_array[$i]))
1115 $set .= ", ".$this->_bcc_array[$i];
1116
1117 if ($i == $float)
1118 {
1119 $chunk[] = substr($set, 1);
1120 $float = $float + $this->bcc_batch_size;
1121 $set = "";
1122 }
1123
1124 if ($i == count($this->_bcc_array)-1)
1125 $chunk[] = substr($set, 1);
1126 }
1127
1128 for ($i = 0; $i < count($chunk); $i++)
1129 {
1130 unset($this->_headers['Bcc']);
1131 unset($bcc);
1132
1133 $bcc = $this->_str_to_array($chunk[$i]);
1134 $bcc = $this->clean_email($bcc);
1135
1136 if ($this->protocol != 'smtp')
1137 $this->_set_header('Bcc', implode(", ", $bcc));
1138 else
1139 $this->_bcc_array = $bcc;
1140
1141 $this->_build_message();
1142 $this->_spool_email();
1143 }
1144 }
1145 // END batch_bcc_send()
1146
1147 // --------------------------------------------------------------------
1148
1149 /**
1150 * Unwrap special elements
1151 *
1152 * @access private
1153 * @return void
1154 */
1155 function _unwrap_specials()
1156 {
1157 $this->_finalbody = preg_replace_callback("/\{unwrap\}(.*?)\{\/unwrap\}/si", array($this, '_remove_nl_callback'), $this->_finalbody);
1158 }
1159 // END _unwrap_specials()
1160
1161 // --------------------------------------------------------------------
1162
1163 /**
1164 * Strip line-breaks via callback
1165 *
1166 * @access private
1167 * @return string
1168 */
1169 function _remove_nl_callback($matches)
1170 {
1171 return preg_replace("/(\r\n)|(\r)|(\n)/", "", $matches['1']);
1172 }
1173 // END _remove_nl_callback()
1174
1175 // --------------------------------------------------------------------
1176
1177 /**
1178 * Spool mail to the mail server
1179 *
1180 * @access private
1181 * @return bol
1182 */
1183 function _spool_email()
1184 {
1185 $this->_unwrap_specials();
1186
1187 switch ($this->_get_protocol())
1188 {
1189 case 'mail' :
1190
1191 if ( ! $this->_send_with_mail())
1192 {
1193 $this->_set_error_message('email_send_failure_phpmail');
1194 return FALSE;
1195 }
1196 break;
1197 case 'sendmail' :
1198
1199 if ( ! $this->_send_with_sendmail())
1200 {
1201 $this->_set_error_message('email_send_failure_sendmail');
1202 return FALSE;
1203 }
1204 break;
1205 case 'smtp' :
1206
1207 if ( ! $this->_send_with_smtp())
1208 {
1209 $this->_set_error_message('email_send_failure_smtp');
1210 return FALSE;
1211 }
1212 break;
1213
1214 }
1215
1216 $this->_set_error_message('email_sent', $this->_get_protocol());
1217 return true;
1218 }
1219 // END _spool_email()
1220
1221 // --------------------------------------------------------------------
1222
1223 /**
1224 * Send using mail()
1225 *
1226 * @access private
1227 * @return bool
1228 */
1229 function _send_with_mail()
1230 {
1231 if ($this->_safe_mode == TRUE)
1232 {
1233 if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str))
1234 return FALSE;
1235 else
1236 return TRUE;
1237 }
1238 else
1239 {
1240 if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, "-f".$this->clean_email($this->_headers['From'])))
1241 return FALSE;
1242 else
1243 return TRUE;
1244 }
1245 }
1246 // END _send_with_mail()
1247
1248 // --------------------------------------------------------------------
1249
1250 /**
1251 * Send using Sendmail
1252 *
1253 * @access private
1254 * @return bool
1255 */
1256 function _send_with_sendmail()
1257 {
1258 $fp = @popen($this->mailpath . " -oi -f ".$this->clean_email($this->_headers['From'])." -t", 'w');
1259
1260 if ( ! is_resource($fp))
1261 {
1262 $this->_set_error_message('email_no_socket');
1263 return FALSE;
1264 }
1265
1266 fputs($fp, $this->_header_str);
1267 fputs($fp, $this->_finalbody);
1268 pclose($fp) >> 8 & 0xFF;
1269
1270 return TRUE;
1271 }
1272 // END _send_with_sendmail()
1273
1274 // --------------------------------------------------------------------
1275
1276 /**
1277 * Send using SMTP
1278 *
1279 * @access private
1280 * @return bool
1281 */
1282 function _send_with_smtp()
1283 {
1284 if ($this->smtp_host == '')
1285 {
1286 $this->_set_error_message('email_no_hostname');
1287 return FALSE;
1288 }
1289
1290 $this->_smtp_connect();
1291 $this->_smtp_authenticate();
1292
1293 $this->_send_command('from', $this->clean_email($this->_headers['From']));
1294
1295 foreach($this->_recipients as $val)
1296 $this->_send_command('to', $val);
1297
1298 if (count($this->_cc_array) > 0)
1299 {
1300 foreach($this->_cc_array as $val)
1301 {
1302 if ($val != "")
1303 $this->_send_command('to', $val);
1304 }
1305 }
1306
1307 if (count($this->_bcc_array) > 0)
1308 {
1309 foreach($this->_bcc_array as $val)
1310 {
1311 if ($val != "")
1312 $this->_send_command('to', $val);
1313 }
1314 }
1315
1316 $this->_send_command('data');
1317
1318 $this->_send_data($this->_header_str . $this->_finalbody);
1319
1320 $this->_send_data('.');
1321
1322 $reply = $this->_get_smtp_data();
1323
1324 $this->_set_error_message($reply);
1325
1326 if (substr($reply, 0, 3) != '250')
1327 {
1328 $this->_set_error_message('email_smtp_error', $reply);
1329 return FALSE;
1330 }
1331
1332 $this->_send_command('quit');
1333 return true;
1334 }
1335 // END _send_with_smtp()
1336
1337 // --------------------------------------------------------------------
1338
1339 /**
1340 * SMTP Connect
1341 *
1342 * @access public
1343 * @param string
1344 * @return string
1345 */
1346 function _smtp_connect()
1347 {
1348
1349 $this->_smtp_connect = fsockopen($this->smtp_host,
1350 $this->smtp_port,
1351 $errno,
1352 $errstr,
1353 $this->smtp_timeout);
1354
1355 if( ! is_resource($this->_smtp_connect))
1356 {
1357 $this->_set_error_message('email_smtp_error', $errno." ".$errstr);
1358 return FALSE;
1359 }
1360
1361 $this->_set_error_message($this->_get_smtp_data());
1362 return $this->_send_command('hello');
1363 }
1364 // END _smtp_connect()
1365
1366 // --------------------------------------------------------------------
1367
1368 /**
1369 * Send SMTP command
1370 *
1371 * @access private
1372 * @param string
1373 * @param string
1374 * @return string
1375 */
1376 function _send_command($cmd, $data = '')
1377 {
1378 switch ($cmd)
1379 {
1380 case 'hello' :
1381
1382 if ($this->_smtp_auth OR $this->_get_encoding() == '8bit')
1383 $this->_send_data('EHLO '.$this->_get_hostname());
1384 else
1385 $this->_send_data('HELO '.$this->_get_hostname());
1386
1387 $resp = 250;
1388 break;
1389 case 'from' :
1390
1391 $this->_send_data('MAIL FROM:<'.$data.'>');
1392
1393 $resp = 250;
1394 break;
1395 case 'to' :
1396
1397 $this->_send_data('RCPT TO:<'.$data.'>');
1398
1399 $resp = 250;
1400 break;
1401 case 'data' :
1402
1403 $this->_send_data('DATA');
1404
1405 $resp = 354;
1406 break;
1407 case 'quit' :
1408
1409 $this->_send_data('QUIT');
1410
1411 $resp = 221;
1412 break;
1413 }
1414
1415 $reply = $this->_get_smtp_data();
1416
1417 $this->_debug_msg[] = "<pre>".$cmd.": ".$reply."</pre>";
1418
1419 if (substr($reply, 0, 3) != $resp)
1420 {
1421 $this->_set_error_message('email_smtp_error', $reply);
1422 return FALSE;
1423 }
1424
1425 if ($cmd == 'quit')
1426 fclose($this->_smtp_connect);
1427
1428 return true;
1429 }
1430 // END _send_command()
1431
1432 // --------------------------------------------------------------------
1433
1434 /**
1435 * SMTP Authenticate
1436 *
1437 * @access private
1438 * @return bool
1439 */
1440 function _smtp_authenticate()
1441 {
1442 if ( ! $this->_smtp_auth)
1443 return true;
1444
1445 if ($this->smtp_user == "" AND $this->smtp_pass == "")
1446 {
1447 $this->_set_error_message('email_no_smtp_unpw');
1448 return FALSE;
1449 }
1450
1451 $this->_send_data('AUTH LOGIN');
1452
1453 $reply = $this->_get_smtp_data();
1454
1455 if (substr($reply, 0, 3) != '334')
1456 {
1457 $this->_set_error_message('email_filed_smtp_login', $reply);
1458 return FALSE;
1459 }
1460
1461 $this->_send_data(base64_encode($this->smtp_user));
1462
1463 $reply = $this->_get_smtp_data();
1464
1465 if (substr($reply, 0, 3) != '334')
1466 {
1467 $this->_set_error_message('email_smtp_auth_un', $reply);
1468 return FALSE;
1469 }
1470
1471 $this->_send_data(base64_encode($this->smtp_pass));
1472
1473 $reply = $this->_get_smtp_data();
1474
1475 if (substr($reply, 0, 3) != '235')
1476 {
1477 $this->_set_error_message('email_smtp_auth_pw', $reply);
1478 return FALSE;
1479 }
1480
1481 return true;
1482 }
1483 // END _smtp_authenticate()
1484
1485 // --------------------------------------------------------------------
1486
1487 /**
1488 * Send SMTP data
1489 *
1490 * @access private
1491 * @return bool
1492 */
1493 function _send_data($data)
1494 {
1495 if ( ! fwrite($this->_smtp_connect, $data . $this->newline))
1496 {
1497 $this->_set_error_message('email_smtp_data_failure', $data);
1498 return FALSE;
1499 }
1500 else
1501 return true;
1502 }
1503 // END _send_data()
1504
1505 // --------------------------------------------------------------------
1506
1507 /**
1508 * Get SMTP data
1509 *
1510 * @access private
1511 * @return string
1512 */
1513 function _get_smtp_data()
1514 {
1515 $data = "";
1516
1517 while ($str = fgets($this->_smtp_connect, 512))
1518 {
1519 $data .= $str;
1520
1521 if (substr($str, 3, 1) == " ")
1522 break;
1523 }
1524
1525 return $data;
1526 }
1527 // END _get_smtp_data()
1528
1529 // --------------------------------------------------------------------
1530
1531 /**
1532 * Get Hostname
1533 *
1534 * @access private
1535 * @return string
1536 */
1537 function _get_hostname()
1538 {
1539 return ($this->smtp_host != '') ? $this->smtp_host : $this->_get_ip();
1540 }
1541 // END _get_hostname()
1542
1543 // --------------------------------------------------------------------
1544
1545 /**
1546 * Get IP
1547 *
1548 * @access private
1549 * @return string
1550 */
1551 function _get_ip()
1552 {
1553 if ($this->_IP !== FALSE)
1554 {
1555 return $this->_IP;
1556 }
1557
1558 $cip = (isset($_SERVER['HTTP_CLIENT_IP']) AND $_SERVER['HTTP_CLIENT_IP'] != "") ? $_SERVER['HTTP_CLIENT_IP'] : FALSE;
1559 $rip = (isset($_SERVER['REMOTE_ADDR']) AND $_SERVER['REMOTE_ADDR'] != "") ? $_SERVER['REMOTE_ADDR'] : FALSE;
1560 $fip = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND $_SERVER['HTTP_X_FORWARDED_FOR'] != "") ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE;
1561
1562 if ($cip && $rip) $this->_IP = $cip;
1563 elseif ($rip) $this->_IP = $rip;
1564 elseif ($cip) $this->_IP = $cip;
1565 elseif ($fip) $this->_IP = $fip;
1566
1567 if (strstr($this->_IP, ','))
1568 {
1569 $x = explode(',', $this->_IP);
1570 $this->_IP = end($x);
1571 }
1572
1573 if ( ! preg_match( "/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/", $this->_IP))
1574 $this->_IP = '0.0.0.0';
1575
1576 unset($cip);
1577 unset($rip);
1578 unset($fip);
1579
1580 return $this->_IP;
1581 }
1582 // END _get_ip()
1583
1584 // --------------------------------------------------------------------
1585
1586 /**
1587 * Get Debugg Message
1588 *
1589 * @access public
1590 * @return string
1591 */
1592 function print_debugger()
1593 {
1594 $msg = '';
1595
1596 if (count($this->_debug_msg) > 0)
1597 {
1598 foreach ($this->_debug_msg as $val)
1599 {
1600 $msg .= $val;
1601 }
1602 }
1603
1604 $msg .= "<pre>".$this->_header_str."\n".$this->_subject."\n".$this->_finalbody.'</pre>';
1605 return $msg;
1606 }
1607 // print_debugger()
1608
1609 // --------------------------------------------------------------------
1610
1611 /**
1612 * Set Message
1613 *
1614 * @access public
1615 * @param string
1616 * @return string
1617 */
1618 function _set_error_message($msg, $val = '')
1619 {
1620 $obj =& get_instance();
1621 $obj->lang->load('email');
1622
1623 if (FALSE === ($line = $obj->lang->line($msg)))
1624 {
1625 $this->_debug_msg[] = str_replace('%s', $val, $msg)."<br />";
1626 }
1627 else
1628 {
1629 $this->_debug_msg[] = str_replace('%s', $val, $line)."<br />";
1630 }
1631 }
1632 // END _set_error_message()
1633
1634 // --------------------------------------------------------------------
1635
1636 /**
1637 * Mime Types
1638 *
1639 * @access private
1640 * @param string
1641 * @return string
1642 */
1643 function _mime_types($ext = "")
1644 {
1645 $mimes = array( 'hqx' => 'application/mac-binhex40',
1646 'cpt' => 'application/mac-compactpro',
1647 'doc' => 'application/msword',
1648 'bin' => 'application/macbinary',
1649 'dms' => 'application/octet-stream',
1650 'lha' => 'application/octet-stream',
1651 'lzh' => 'application/octet-stream',
1652 'exe' => 'application/octet-stream',
1653 'class' => 'application/octet-stream',
1654 'psd' => 'application/octet-stream',
1655 'so' => 'application/octet-stream',
1656 'sea' => 'application/octet-stream',
1657 'dll' => 'application/octet-stream',
1658 'oda' => 'application/oda',
1659 'pdf' => 'application/pdf',
1660 'ai' => 'application/postscript',
1661 'eps' => 'application/postscript',
1662 'ps' => 'application/postscript',
1663 'smi' => 'application/smil',
1664 'smil' => 'application/smil',
1665 'mif' => 'application/vnd.mif',
1666 'xls' => 'application/vnd.ms-excel',
1667 'ppt' => 'application/vnd.ms-powerpoint',
1668 'wbxml' => 'application/vnd.wap.wbxml',
1669 'wmlc' => 'application/vnd.wap.wmlc',
1670 'dcr' => 'application/x-director',
1671 'dir' => 'application/x-director',
1672 'dxr' => 'application/x-director',
1673 'dvi' => 'application/x-dvi',
1674 'gtar' => 'application/x-gtar',
1675 'php' => 'application/x-httpd-php',
1676 'php4' => 'application/x-httpd-php',
1677 'php3' => 'application/x-httpd-php',
1678 'phtml' => 'application/x-httpd-php',
1679 'phps' => 'application/x-httpd-php-source',
1680 'js' => 'application/x-javascript',
1681 'swf' => 'application/x-shockwave-flash',
1682 'sit' => 'application/x-stuffit',
1683 'tar' => 'application/x-tar',
1684 'tgz' => 'application/x-tar',
1685 'xhtml' => 'application/xhtml+xml',
1686 'xht' => 'application/xhtml+xml',
1687 'zip' => 'application/zip',
1688 'mid' => 'audio/midi',
1689 'midi' => 'audio/midi',
1690 'mpga' => 'audio/mpeg',
1691 'mp2' => 'audio/mpeg',
1692 'mp3' => 'audio/mpeg',
1693 'aif' => 'audio/x-aiff',
1694 'aiff' => 'audio/x-aiff',
1695 'aifc' => 'audio/x-aiff',
1696 'ram' => 'audio/x-pn-realaudio',
1697 'rm' => 'audio/x-pn-realaudio',
1698 'rpm' => 'audio/x-pn-realaudio-plugin',
1699 'ra' => 'audio/x-realaudio',
1700 'rv' => 'video/vnd.rn-realvideo',
1701 'wav' => 'audio/x-wav',
1702 'bmp' => 'image/bmp',
1703 'gif' => 'image/gif',
1704 'jpeg' => 'image/jpeg',
1705 'jpg' => 'image/jpeg',
1706 'jpe' => 'image/jpeg',
1707 'png' => 'image/png',
1708 'tiff' => 'image/tiff',
1709 'tif' => 'image/tiff',
1710 'css' => 'text/css',
1711 'html' => 'text/html',
1712 'htm' => 'text/html',
1713 'shtml' => 'text/html',
1714 'txt' => 'text/plain',
1715 'text' => 'text/plain',
1716 'log' => 'text/plain',
1717 'rtx' => 'text/richtext',
1718 'rtf' => 'text/rtf',
1719 'xml' => 'text/xml',
1720 'xsl' => 'text/xml',
1721 'mpeg' => 'video/mpeg',
1722 'mpg' => 'video/mpeg',
1723 'mpe' => 'video/mpeg',
1724 'qt' => 'video/quicktime',
1725 'mov' => 'video/quicktime',
1726 'avi' => 'video/x-msvideo',
1727 'movie' => 'video/x-sgi-movie',
1728 'doc' => 'application/msword',
1729 'word' => 'application/msword',
1730 'xl' => 'application/excel',
1731 'eml' => 'message/rfc822'
1732 );
1733
1734 return ( ! isset($mimes[strtolower($ext)])) ? "application/x-unknown-content-type" : $mimes[strtolower($ext)];
1735 }
1736 // END _mime_types()
1737
1738}
1739// END CI_Email class
1740?>