* $email = new classEmail( * array( 'debug' => 1, * 'method' => 'mail', * 'html' => 1, * 'debug_path' => '/tmp/_mail', * 'charset' => 'utf-8', * ) * ); * $email->setFrom( "dont@mail.me", "This is\r\nan email" ); * $email->setTo( "me@mydomain.com" ); * $email->addBCC( "myfriend@mydomain.com" ); * $email->addBCC( "myotherfriend@mydomain.com" ); * $email->setSubject( "This is a test!!" ); * $email->setBody( "We have HTML capability!

But this is just a test..." ); * $email->sendMail(); * */ /** * Email class interface * */ interface interfaceEmail { /** * Constructor * * @access public * @param array Initiate class parameters * @return void */ public function __construct( $opts=array() ); /** * Clear stored data to prepare a new email. Useful * to prevent having to close/reopen SMTP connection * repeatedly. * * @access public * @return void */ public function clearEmail(); /** * Clear stored errors to prepare a new email. * * @access public * @return void */ public function clearError(); /** * Set the from email address * * @access public * @param string From email address * @param string [Optional] From display * @return boolean */ public function setFrom( $email, $display='' ); /** * Set the 'to' email address * * @access public * @param string To email address * @return boolean */ public function setTo( $email ); /** * Add bcc's * * @access public * @param string To email address * @return boolean */ public function addBCC( $email ); /** * Set the email subject * * @access public * @param string Email subject * @return boolean */ public function setSubject( $subject ); /** * Set the email body * * @access public * @param string Email body * @return boolean */ public function setBody( $body ); /** * Set a header manually * * @access public * @param string Header key * @param string Header value * @return boolean */ public function setHeader( $key, $value ); /** * Send the mail (All appropriate params must be set by this point) * * @access public * @return boolean Mail sent successfully */ public function sendMail(); /** * Add an attachment to the current email * * @access public * @param string File data * @param string File name * @param string File type (MIME) * @return void */ public function addAttachment( $data="", $name="", $ctype='application/octet-stream' ); } /** * Email class * */ class classEmail implements interfaceEmail { /** * From email address * * @access private * @var string */ private $from = ""; /** * From email address (displayed) * * @access private * @var string */ private $from_display = ""; /** * To email address * * @access private * @var string */ private $to = ""; /** * Email subject * * @access private * @var string */ private $subject = ""; /** * Email message contents * * @access private * @var string */ private $message = ""; /** * PHP mail() extra params * * @access private * @var string */ private $extra_opts = ''; /** * Plain text message contents * * @access private * @var string */ private $pt_message = ""; /** * Attachments: Parts * * @access private * @var array */ private $parts = array(); /** * BCC Email addresses * * @access private * @var array */ private $bcc = array(); /** * Email headers * * @access private * @var array */ private $mail_headers = array(); /** * Header EOL * RFC specs state \r\n * However most servers seem to only support \n * * @access public * @var string */ const header_eol = "\n"; /** * Attachments: Multi-part * * @access private * @var string */ private $multipart = ""; /** * Attachments: Boundry * * @access private * @var string */ private $boundry = "----=_NextPart_000_0022_01C1BD6C.D0C0F9F0"; /** * HTML email flag * * @access private * @var integer */ private $html_email = 0; /** * Email character set * * @access private * @var string */ private $char_set = 'utf-8'; /** * SMTP: Resource * * @access private * @var resource */ private $smtp_fp = null; /** * SMTP: Message * * @access public * @var string */ public $smtp_msg = ""; /** * SMTP: Port * * @access private * @var integer */ private $smtp_port = 25; /** * SMTP: Host * * @access private * @var string */ private $smtp_host = "localhost"; /** * SMTP: Username * * @access private * @var string */ private $smtp_user = ""; /** * SMTP: Password * * @access private * @var string */ private $smtp_pass = ""; /** * SMTP: HELO or EHLO * * @access public * @var string */ public $smtp_helo = "HELO"; /** * SMTP: Return code * * @access public * @var string */ public $smtp_code = ""; /** * SMTP: Wrap email addresses in brackets flag * * @access private * @var boolean */ private $wrap_brackets = false; /** * Default email method (mail or smtp) * * @access private * @var string */ private $mail_method = 'mail'; /** * Dump email to flat file for testing * * @access private * @var integer */ private $temp_dump = 0; /** * Path for email dumps * * @access private * @var string */ private $temp_dump_path = ''; /** * Error message * * @access public * @var string */ public $error_msg = ''; /** * Error description * * @access public * @var string */ public $error_help = ''; /** * Error flag * * @access public * @var boolean */ public $error = false; /** * Constructor * * @access public * @param array Initiate class parameters * @return void */ public function __construct( $opts=array() ) { $this->mail_method = ( $opts['method'] AND in_array( strtolower($opts['method']), array( 'smtp', 'mail' ) ) ) ? strtolower($opts['method']) : 'mail'; $this->temp_dump = ( isset($opts['debug']) AND $opts['debug'] ) ? 1 : 0; $this->temp_dump_path = ( isset($opts['debug_path']) AND $opts['debug_path'] ) ? $opts['debug_path'] : ''; $this->html_email = ( isset($opts['html']) AND $opts['html'] ) ? 1 : 0; $this->char_set = ( isset($opts['charset']) AND $opts['charset'] ) ? $opts['charset'] : 'utf-8'; $this->smtp_host = ( isset($opts['smtp_host']) AND $opts['smtp_host'] ) ? $opts['smtp_host'] : ''; $this->smtp_port = ( isset($opts['smtp_port']) AND $opts['smtp_port'] ) ? intval($opts['smtp_port']) : 25; $this->smtp_user = ( isset($opts['smtp_user']) AND $opts['smtp_user'] ) ? $opts['smtp_user'] : ''; $this->smtp_pass = ( isset($opts['smtp_pass']) AND $opts['smtp_pass'] ) ? $opts['smtp_pass'] : ''; $this->smtp_helo = ( isset($opts['smtp_helo']) AND $opts['smtp_helo'] ) ? $opts['smtp_helo'] : 'HELO'; $this->wrap_brackets = ( isset($opts['wrap_brackets']) AND $opts['wrap_brackets'] ) ? true : false; $this->extra_opts = ( isset($opts['extra_opts']) AND $opts['extra_opts'] ) ? $opts['extra_opts'] : ''; if( $this->mail_method == 'smtp' ) { $this->_smtpConnect(); } } /** * Destructor * * @access public * @return void */ public function __destruct() { if( $this->mail_method == 'smtp' ) { $this->_smtpDisconnect(); } } /** * Clear stored data to prepare a new email. Useful * to prevent having to close/reopen SMTP connection * repeatedly. * * @access public * @return void */ public function clearEmail() { $this->from = ''; $this->from_display = ''; $this->to = ''; $this->bcc = array(); $this->subject = ''; $this->message = ''; $this->pt_message = ''; $this->parts = array(); $this->mail_headers = array(); $this->multipart = ''; $this->smtp_msg = ''; $this->smtp_code = ''; } /** * Clear stored errors to prepare a new email. * * @access public * @return void */ public function clearError() { $this->error_msg = ''; $this->error_help = ''; $this->error = false; } /** * Set the from email address * * @access public * @param string From email address * @param string [Optional] From display * @return boolean */ public function setFrom( $email, $display='' ) { $this->from = $this->_cleanEmail( $email ); /* Fix encoded quotes, etc */ $from = str_replace( '"', '"', $display ); $from = str_replace( ''', "'", $from ); $from = str_replace( ''' , "'", $from ); $from = str_replace( '!' , "!", $from ); $from = str_replace( '$' , "$", $from ); if( $this->mail_method != 'smtp' AND $from !== '' ) { $fheader = $this->_encodeHeaders( array( 'FDispay' => $from ) ); $from = $fheader['FDispay']; unset($this->mail_headers['FDispay']); } $this->from_display = $from; return true; } /** * Set a header manually * * @access public * @param string Header key * @param string Header value * @return boolean */ public function setHeader( $key, $value ) { $this->mail_headers[ $key ] = $value; return true; } /** * Set the 'to' email address * * @access public * @param string To email address * @return boolean */ public function setTo( $email ) { $this->to = $this->_cleanEmail( $email ); return true; } /** * Add bcc's * * @access public * @param string To email address * @return boolean */ public function addBCC( $email ) { $this->bcc[] = $this->_cleanEmail( $email ); return true; } /** * Set the email subject * * @access public * @param string Email subject * @return boolean */ public function setSubject( $subject ) { /* Fix encoded quotes, etc */ $subject = str_replace( '"', '"', $subject ); $subject = str_replace( ''', "'", $subject ); $subject = str_replace( ''' , "'", $subject ); $subject = str_replace( '!' , "!", $subject ); $subject = str_replace( '$' , "$", $subject ); if( $this->mail_method != 'smtp' ) { $sheader = $this->_encodeHeaders( array( 'Subject' => $subject ) ); $subject = $sheader['Subject']; } $this->subject = $subject; return true; } /** * Set the email body * * @access public * @param string Email body * @return boolean */ public function setBody( $body ) { $this->message = $body; return true; } /** * Clean an email address * * @access private * @param string Email address * @return string Cleaned email address */ private function _cleanEmail( $email ) { $email = str_replace( ' ' , '', $email ); $email = str_replace( "\t" , '', $email ); $email = str_replace( "\r" , '', $email ); $email = str_replace( "\n" , '', $email ); $email = str_replace( ',,' , ',', $email ); $email = preg_replace( "#\#\[\]'\"\(\):;/\$!ᆪ%\^&\*\{\}#" , "", $email ); return $email; } /** * Send the mail (All appropriate params must be set by this point) * * @access public * @return boolean Mail sent successfully */ public function sendMail() { //----------------------------------------- // Build headers //----------------------------------------- $this->_buildHeaders(); //----------------------------------------- // Verify params are all set //----------------------------------------- if( !$this->to OR !$this->from OR !$this->subject ) { $this->_fatalError( "Пустое поле От, Кому или Тема" ); return false; } //----------------------------------------- // Debugging //----------------------------------------- if( $this->temp_dump == 1 ) { $debug = $this->subject . "\n------------\n" . $this->rfc_headers . "\n\n" . $this->message; if( !is_dir( $this->temp_dump_path ) ) { @mkdir( $this->temp_dump_path ); @chmod( $this->temp_dump_path, 0777 ); } if( !is_dir( $this->temp_dump_path ) ) { $this->_fatalError( "Включена отладка, но путь отладки не существует и не может быть создан" ); return false; } $pathy = $this->temp_dump_path . '/' . date("M-j-Y,hi-A") . str_replace( '@', '+', $this->to ) . '.php'; $fh = @fopen( $pathy, 'w' ); @fputs( $fh, $debug, strlen($debug) ); @fclose( $fh ); } else { //----------------------------------------- // PHP mail() //----------------------------------------- if( $this->mail_method != 'smtp' ) { if ( ! @mail( $this->to, $this->subject, $this->message, $this->rfc_headers, $this->extra_opts ) ) { if ( ! @mail( $this->to, $this->subject, $this->message, $this->rfc_headers ) ) { $this->_fatalError( "Невозможно отправить сообщение", "Ошибка функции 'mail'" ); } } } //----------------------------------------- // SMTP //----------------------------------------- else { $this->_smtpSendMail(); } } $this->clearEmail(); return $this->error ? false : true; } /** * Fatal error handler * * @access private * @param string Error Message * @param string Error Help / Description * @return boolean */ private function _fatalError( $msg, $help="" ) { $this->error = true; $this->error_msg = $msg; $this->error_help = $help; return false; } /*-------------------------------------------------------------------------*/ // HEADERS /*-------------------------------------------------------------------------*/ /** * Build the multipart headers for the email * * @access private * @return string Multipart headers */ private function _buildMultipart() { $multipart = ''; for( $i = sizeof( $this->parts ) - 1 ; $i >= 0 ; $i-- ) { $multipart .= self::header_eol . $this->_encodeAttachment( $this->parts[$i] ) . "--" . $this->boundry; } return $multipart . "--\n"; } /** * ENCODE HEADERS - RFC2047 * * @access private * @param array Array of headers * @return array Headers encoded per RFCs * @see http://www.faqs.org/rfcs/rfc822.html * @see http://www.faqs.org/rfcs/rfc2045 * @see http://www.faqs.org/rfcs/rfc2047 * @see http://us2.php.net/manual/en/function.mail.php#27997 */ private function _encodeHeaders( $headers = array() ) { $enc_headers = count($headers) ? $headers : $this->mail_headers; foreach( $enc_headers as $header => $value) { $orig_value = $value; //----------------------------------------- // MTAs seem to dislike 'From' encoded // so we just strip board name and continue //----------------------------------------- if( $header == 'From' OR $header == 'Content-Type' OR $header == 'Content-Disposition' ) { $this->mail_headers[ $header ] = $orig_value; $enc_headers[ $header ] = $orig_value; continue; } //----------------------------------------- // We don't want to keep subject in the // headers for php mail //----------------------------------------- if( $this->mail_method != 'smtp' AND $header == 'Subject' ) { continue; } //----------------------------------------- // Don't bother encoding unless we have chars // that need to be encoded //----------------------------------------- if( !preg_match( '/(\w*[\x80-\xFF]+\w*)/', $value ) ) { $this->mail_headers[ $header ] = $orig_value; $enc_headers[ $header ] = $orig_value; continue; } //----------------------------------------- // Base64 encoding from example at php.net //----------------------------------------- $start = '=?' . $this->char_set . '?B?'; $end = '?='; $spacer = $end . self::header_eol . ' ' . $start; $length = 75 - strlen($start) - strlen($end); $length = $length - ($length % 4); $value = base64_encode($value); $value = chunk_split( $value, $length, $spacer ); $spacer = preg_quote($spacer); $value = preg_replace( "/" . $spacer . "$/", "", $value ); $value = $start . $value . $end; if( !count($headers) ) { $this->mail_headers[ $header ] = $value; } else { $enc_headers[ $header ] = $value; } } return $enc_headers; } /** * Build the email headers (MIME, Charset, From, BCC, To, Subject, etc) * * @access private * @return void */ private function _buildHeaders() { $extra_headers = array(); $extra_header_rfc = ""; //----------------------------------------- // HTML (hitmuhl) // If we're sending HTML messages, then // we'll add the plain text message along with // it for non HTML browsers //----------------------------------------- $this->pt_message = $this->message; $this->pt_message = str_replace( "
", "\n", $this->pt_message ); $this->pt_message = str_replace( "
" , "\n", $this->pt_message ); $this->pt_message = strip_tags( $this->pt_message ); $this->pt_message = html_entity_decode( $this->pt_message, ENT_QUOTES ); $this->pt_message = str_replace( '\', '\\', $this->pt_message ); $this->pt_message = str_replace( '$', '$', $this->pt_message ); //----------------------------------------- // Start mail headers //----------------------------------------- $this->mail_headers['MIME-Version'] = "1.0"; $this->mail_headers['Date'] = date( "r" ); $this->mail_headers['Return-Path'] = $this->from; $this->mail_headers['X-Priority'] = "3"; $this->mail_headers['X-MSMail-Priority'] = "Normal"; $this->mail_headers['X-Mailer'] = "IPS PHP Mailer"; //----------------------------------------- // From and to... //----------------------------------------- if( $this->from_display AND !preg_match( '/(\w*[\x80-\xFF]+\w*)/', $this->from_display ) ) { $this->mail_headers['From'] = '"' . $this->from_display . '" <' . $this->from . '>'; } else { $this->mail_headers['From'] = '<' . $this->from . '>'; } if ( $this->mail_method != 'smtp' ) { if( count( $this->bcc ) > 0 ) { $this->mail_headers['Bcc'] = implode( "," , $this->bcc ); } } else { if ( $this->to ) { $this->mail_headers['To'] = $this->to; } $this->mail_headers['Subject'] = $this->subject; } //----------------------------------------- // Attachments? //----------------------------------------- if ( count($this->parts) > 0 ) { if ( ! $this->html_email ) { $extra_headers[0]['Content-Type'] = "multipart/mixed;\n\tboundary=\"".$this->boundry."\""; $extra_headers[0]['notencode'] = "\n\nThis is a MIME encoded message.\n\n--".$this->boundry."\n"; $extra_headers[1]['Content-Type'] = "text/plain;\n\tcharset=\"".$this->char_set."\""; $extra_headers[1]['notencode'] = "\n\n".$this->message."\n\n--".$this->boundry; } else { $extra_headers[0]['Content-Type'] = "multipart/mixed;\n\tboundary=\"".$this->boundry."\""; $extra_headers[0]['notencode'] = "\n\nThis is a MIME encoded message.\n\n--".$this->boundry."\n"; $extra_headers[1]['Content-Type'] = "text/html;\n\tcharset=\"".$this->char_set."\""; $extra_headers[1]['notencode'] = "\n\n".$this->message."\n\n--".$this->boundry; } $extra_headers[2]['notencode'] = $this->_buildMultipart(); reset($extra_headers); foreach( $extra_headers as $subset => $the_header ) { foreach( $the_header as $k => $v ) { if( $k == 'notencode' ) { $extra_headers_rfc .= $v; } else { $v = $this->_encodeHeaders( array( 'v' => $v ) ); $extra_headers_rfc .= $k . ': ' . $v['v'] . self::header_eol; } } } $this->message = ""; } else { //----------------------------------------- // HTML (hitmuhl) ? //----------------------------------------- if ( $this->html_email ) { $extra_headers[0]['Content-Type'] = "multipart/alternative;\n\tboundary=\"".$this->boundry."\""; $extra_headers[0]['notencode'] = "\n\nThis is a MIME encoded message.\n\n--".$this->boundry."\n"; $extra_headers[1]['Content-Type'] = "text/plain;\n\tcharset=\"".$this->char_set."\""; $extra_headers[1]['notencode'] = "\n\n".$this->pt_message."\n\n--".$this->boundry."\n"; $extra_headers[2]['Content-Type'] = "text/html;\n\tcharset=\"".$this->char_set."\""; $extra_headers[2]['notencode'] = "\n\n".$this->message."\n\n"; reset($extra_headers); foreach( $extra_headers as $subset => $the_header ) { foreach( $the_header as $k => $v ) { if( $k == 'notencode' ) { $extra_headers_rfc .= $v; } else { $v = $this->_encodeHeaders( array( 'v' => $v ) ); $extra_headers_rfc .= $k . ': ' . $v['v'] . self::header_eol; } } } $this->message = ""; } else { $this->mail_headers['Content-type'] = 'text/plain; charset="'.$this->char_set.'"'; } } $this->_encodeHeaders(); foreach( $this->mail_headers as $k => $v ) { $this->rfc_headers .= $k . ": " . $v . self::header_eol; } //----------------------------------------- // Attachments extra? //----------------------------------------- if( $extra_headers_rfc ) { $this->rfc_headers .= $extra_headers_rfc; } } /*-------------------------------------------------------------------------*/ // SMTP Methods /*-------------------------------------------------------------------------*/ /** * SMTP connect * * @access private * @return boolean Connection successful */ private function _smtpConnect() { $this->smtp_fp = @fsockopen( $this->smtp_host, intval($this->smtp_port), $errno, $errstr, 30 ); if ( ! $this->smtp_fp ) { $this->_smtpError( "Невозможно соединиться с SMTP сервером ({$errno}:{$errstr})" ); return false; } $this->_smtpGetLine(); $this->smtp_code = substr( $this->smtp_msg, 0, 3 ); if ( $this->smtp_code == 220 ) { //----------------------------------------- // HELO!, er... HELLO! //----------------------------------------- $this->_smtpSendCmd( "{$this->smtp_helo} " . $this->smtp_host ); if ( $this->smtp_code != 250 ) { $this->_smtpError( "HELO (using: {$this->smtp_helo})" ); return false; } //----------------------------------------- // Do you like my user! //----------------------------------------- if ( $this->smtp_user AND $this->smtp_pass ) { $this->_smtpSendCmd( "AUTH LOGIN" ); if ( $this->smtp_code == 334 ) { $this->_smtpSendCmd( base64_encode($this->smtp_user) ); if ( $this->smtp_code != 334 ) { $this->_smtpError( "Неверное имя пользователя SMTP" ); return false; } $this->_smtpSendCmd( base64_encode($this->smtp_pass) ); if ( $this->smtp_code != 235 ) { $this->_smtpError( "Неверный пароль пользователя SMTP" ); return; } } else { $this->_smtpError( "SMTP cервер не поддерживает авторизацию" ); return; } } } else { $this->_smtpError( "Невозможно соединиться с SMTP сервером" ); return false; } return true; } /** * SMTP disconnect * * @access private * @return boolean Disconnect successful */ private function _smtpDisconnect() { return @fclose( $this->smtp_fp ); } /** * SMTP: Get next line * * @access private * @return void */ private function _smtpGetLine() { $this->smtp_msg = ""; while ( $line = @fgets( $this->smtp_fp, 515 ) ) { $this->smtp_msg .= $line; if ( substr($line, 3, 1) == " " ) { break; } } } /** * SMTP: Send command * * @access private * @param string SMTP command * @return boolean Command successful */ private function _smtpSendCmd( $cmd ) { $this->smtp_msg = ""; $this->smtp_code = ""; @fputs( $this->smtp_fp, $cmd . "\r\n" ); $this->_smtpGetLine(); $this->smtp_code = substr( $this->smtp_msg, 0, 3 ); return $this->smtp_code == "" ? false : true; } /** * Encode data and make it safe for SMTP transport * * @access private * @param string Raw Data * @return string CRLF Encoded Data */ private function _smtpCrlfEncode( $data ) { $data .= "\n"; $data = str_replace( "\n", "\r\n", str_replace( "\r", "", $data ) ); $data = str_replace( "\n.\r\n" , "\n. \r\n", $data ); return $data; } /** * SMTP: Error handler * * @access private * @param string SMTP error * @return boolean */ private function _smtpError( $err="" ) { $this->smtp_msg = $err; $this->_fatalError( $err ); return false; } /** * SMTP: Sends the SMTP email * * @access private * @return void */ private function _smtpSendMail() { $data = $this->_smtpCrlfEncode( $this->rfc_headers . "\n\n" . $this->message ); //----------------------------------------- // Wrap in brackets //----------------------------------------- if ( $this->wrap_brackets ) { if ( ! preg_match( "/^from ) ) { $this->from = "<" . $this->from . ">"; } } //----------------------------------------- // From: //----------------------------------------- $this->_smtpSendCmd( "MAIL FROM:" . $this->from ); if ( $this->smtp_code != 250 ) { $this->_smtpError( "Ошибка команды MAIL FROM" ); return false; } $to_arry = array( $this->to ); if( count( $this->bcc ) > 0 ) { foreach( $this->bcc as $bcc ) { $to_arry[] = $bcc; } } //----------------------------------------- // To: //----------------------------------------- foreach( $to_arry as $to_email ) { if ( $this->wrap_brackets ) { $this->_smtpSendCmd( "RCPT TO:<" . $to_email . ">" ); } else { $this->_smtpSendCmd( "RCPT TO:" . $to_email ); } if ( $this->smtp_code != 250 ) { $this->_smtpError( "Неверный email адрес: $to_email" ); } } //----------------------------------------- // SEND MAIL! //----------------------------------------- $this->_smtpSendCmd( "DATA" ); if ( $this->smtp_code == 354 ) { fputs( $this->smtp_fp, $data . "\r\n" ); } else { $this->_smtpError( "Ошибка передачи сообщения SMTP серверу"); return false; } //----------------------------------------- // GO ON, NAFF OFF! //----------------------------------------- $this->_smtpSendCmd( "." ); if ( $this->smtp_code != 250 ) { $this->_smtpError( "Ошибка отправки письма" ); return false; } $this->_smtpSendCmd( "quit" ); if ( $this->smtp_code != 221 ) { $this->_smtpError( "Невозможно уйти с SMTP сервера с помощью 'quit'" ); return false; } } /*-------------------------------------------------------------------------*/ // ATTACHMENTS /*-------------------------------------------------------------------------*/ /** * Add an attachment to the current email * * @access public * @param string File data * @param string File name * @param string File type (MIME) * @return void */ public function addAttachment( $data="", $name="", $ctype='application/octet-stream' ) { $this->parts[] = array( 'ctype' => $ctype, 'data' => $data, 'encode' => 'base64', 'name' => $name ); } /** * Encode an attachment * * @access private * @param array Raw data [ctype,encode,name,data] * @return string Processed data */ private function _encodeAttachment( $part=array() ) { $msg = chunk_split( base64_encode( $part['data'] ) ); $headers = array(); $header_str = ""; $headers['Content-Type'] = $part['ctype'] . ( $part['name'] ? "; name =\"".$part['name']."\"" : "" ); $headers['Content-Transfer-Encoding'] = $part['encode']; $headers['Content-Disposition'] = "attachment; filename=\"".$part['name']."\""; $headers = $this->_encodeHeaders( $headers ); foreach( $headers as $k => $v ) { $header_str .= $k . ': ' . $v . self::header_eol; } $header_str .= "\n\n" . $msg . "\n"; return $header_str; } }