本类参考了网上关于PHP的MIME MAIL和SMTP发送协议的文章,本类可以在*NUX或WIN平台下并且无需SMTP服务器,直接通过邮件专递方式送到邮件接收方的邮件服务器中。
需要注意的是在发送大尺寸邮件时,建议在服务器允许MAIL()发送的情况下,尽量开启'usemail'=>true,因为用PHP的SOCKE 方式发送效率相对于MAIL()函数来说要低;另外要说明的是由于采用邮件专递的方式邮件没有本地暂存发送,为了可靠性和避免长时间等待的过时问题,所以 在没有启用PHP的MAIL函数时,本类没有添加支持用通过分号分隔的多帐号同时发送的功能。
本类在nease.net的Linux+php5虚拟主机空间(该空间不能使用PHP自带的MAIL函数发邮件,写此类当时就是为了在这个空间下发送邮件)及win2003+IIS6+php4.3上测试成功。
简单范例:
<?php require("mailer.class.php"); $mailer=new mailer(); $mailer->mConfig['mailform']="xxx@21cn.com"; $isended=$mailer->mail("nobody@example.com","the subject","hello","From: webmaster@example.com"); if($isended) { echo "true"; } else { echo "false"; } ?>
类文件: mailer.class.php
<?php /** * Project: Dowebs.Lib: the PHP compiling template engine * File: mailer.lib.php * * This library is opensource software; * @link http://www.dowebs.net/ * @copyright 2004-2005 dowebs.net studio. * @author Xie Hengduo xiejuchen@21cn.com * @package System * @version 1.0.0.0 */ class mailer{ var $mConfig=array( 'dns' =>"202.96.104.16", //设置解域MX记录的域名服务器 'mailform' =>"yourname@yourdomain.com",//发送邮件的帐号 'charset' =>"utf-8", //HTML附件编码 'usemail' =>false //是否使用PHP中的MAIL函数 ); var $dns_repl_domain=""; var $arrMX =array(); var $error =""; var $aattach =array(); var $xheaders =array(); var $ctencoding = "7bit"; var $priorities = array( '1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)' ); var $content_type=''; function mailer() { } //兼容的mail函数 function mail($to,$subject,$message,$additional_headers='') { if($this->mConfig['usemail']) { return mail($to,$subject,$message,$additional_headers); } else { if($this->queryMailStmp($to)) { $this->error="2 收件人邮箱地址非法"; return false; } //连接服务器 $is_sockopen=false; $hostname=""; foreach($this->arrMX as $value) { if($fp = fsockopen ($value, 25, $errno, $errstr, 60)) { $hostname=$value; $is_sockopen=true; break; } } if (!$is_sockopen){$this->error="3 联接服务器失败";return false;} //HELO fputs($fp,"HELO {$hostname}\r\n"); $lastmessage = fgets($fp,1024); if(substr($lastmessage,0,3) != 220 ){$this->error="4 错误信息$lastmessage";return false;} //FROM: fputs( $fp,"MAIL FROM:<{$this->mConfig['mailform']}>"."\r\n"); $lastmessage = fgets ($fp,1024); if (substr($lastmessage,0,3) != 250){$this->error="5 错误信息$lastmessage";return false;} //TO: fputs( $fp,"RCPT TO:<$to>"."\r\n"); $lastmessage = fgets ($fp,1024); if (substr($lastmessage,0,3) != 250){$this->error="6 错误信息$lastmessage";return false;} while(true){ $lastmessage = fgets($fp,512); if((substr($lastmessage,3,1) != "-")||(empty($lastmessage)))break; } //DATA fputs($fp,"DATA\r\n"); $lastmessage = fgets ($fp,1024); if (substr($lastmessage,0,3) != 354){$this->error="7 错误信息$lastmessage";return false;} $message="\n".$message; if($additional_headers!='') { $message = $additional_headers."\r\n".$message; } //处理To头 $head="To: $to\r\n"; $message = $head.$message; //处理Subject头 $head="Subject: $subject\r\n"; $message = $head.$message; //加上结束串 $message .= "\r\n.\r\n"; //发送信息 fputs($fp, $message); fputs($fp,"QUIT\r\n"); fclose($fp); return true; } } //邮址初步校验 function is_valid_email ($email = "") { return preg_match('/^[.\w-]+@([\w-]+\.)+[a-zA-Z]{2,6}$/',$email); } function queryMailStmp($mailaddr) { if($this->is_valid_email($mailaddr)) { $this->mxlookup(substr(strstr($mailaddr,'@'),1)); } else { return false; } } //取得MX记录 function mxlookup($domain) { if(function_exists('getmxrr')) { getmxrr($domain,$this->arrMX); } else { ########################## $dot_pos = 0; $temp = ""; $QNAME=""; while($dot_pos=strpos($domain,".")) { $temp = substr($domain,0,$dot_pos); $domain = substr($domain,$dot_pos+1); $QNAME .= chr(strlen($temp)).$temp; } $QNAME .= chr(strlen($domain)).$domain.chr(0); ########################### $dns_packet = chr(0).chr(1).chr(1).chr(0).chr(0).chr(1).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).$QNAME.chr(0).chr(15).chr(0).chr(1); $dns_socket = fsockopen("udp://{$this->mConfig['dns']}", 53); fwrite($dns_socket,$dns_packet,strlen($dns_packet)); $this->dns_reply = fread($dns_socket,1); $bytes = stream_get_meta_data($dns_socket); $this->dns_reply .= fread($dns_socket,$bytes['unread_bytes']); fclose($dns_socket); $this->cIx=6; $this->Total_Accounts=""; for($i=0;$i<2;$i++){ $this->Total_Accounts.=ord(substr($this->dns_reply,$this->cIx,1)); $this->cIx++; } $this->cIx+=4; $this->parse_data($this->dns_repl_domain); $this->cIx+=7; for($ic=1;$ic<=$this->Total_Accounts;$ic++) { $QTYPE = ord($this->gdi($this->cIx)); if($QTYPE!==15){ print("<font color='red' size='4' face='verdana'><B>[No MX Records returned]</b></font>"); die(); } $this->cIx+=9; $mxPref = ord($this->gdi($this->cIx)); $this->parse_data($curmx); $this->arrMX[] =$curmx; $this->cIx+=3; } } } function gdi(&$cIx,$bytes=1) { $this->cIx++; return(substr($this->dns_reply, $this->cIx-1, $bytes)); } function parse_data(&$retval) { $arName = array(); $byte = ord($this->gdi($this->cIx)); while($byte!==0) { if($byte==192) { //compressed $tmpIx = $this->cIx; $this->cIx = ord($this->gdi($cIx)); $tmpName = $retval; $this->parse_data($tmpName); $retval = $retval.".".$tmpName; $this->cIx = $tmpIx+1; return; } $retval=""; $bCount = $byte; for($b=0;$b<$bCount;$b++) { $retval .= $this->gdi($this->cIx); } $arName[]=$retval; $byte = ord($this->gdi($this->cIx)); } $retval=join(".",$arName); } ############################################ # MIME MAIL CODE ############################################ function From( $from="") { if($from=='') { $this->xheaders['From']=$this->mConfig['mailform']; } else { $this->xheaders['From'] = $from; } } function mimemail($to,$subject,$message) { $this->boundary= "--" . md5( uniqid("myboundary") ); if( $this->mConfig['charset'] != "us-ascii" ) { $this->ctencoding = "8bit"; } $headers = ""; if( $this->mConfig['charset'] != "") { //global $contenttype; $this->xheaders["Mime-Version"] = "1.0"; $this->xheaders["Content-Type"] = "{$this->content_type}; charset={$this->mConfig['charset']}"; $this->xheaders["Content-Transfer-Encoding"] = $this->ctencoding; } $this->xheaders["X-Mailer"] = "Dowebs.net Mailer"; if( count( $this->aattach ) > 0 ) { $this->xheaders["Content-Type"] = "multipart/mixed;\n boundary=\"{$this->boundary}\""; $fullBody="This is a multi-part message in MIME format.\n--{$this->boundary}\n"; $fullBody.= "Content-Type: text/html; charset={$this->mConfig['charset']}\nContent-Transfer-Encoding:{$this->ctencoding}\n\n".message."\n"; $sep= chr(13) . chr(10); $ata= array(); $k=0; for( $i=0; $i < count( $this->aattach); $i++ ) { $filename = $this->aattach[$i]; $basename = basename($filename); $ctype = $this->actype[$i]; // content-type $disposition = $this->adispo[$i]; if(!file_exists( $filename)){$this->error="1 Class Mail, method attach : file {$filename} can't be found";return false;} $subhdr= "--{$this->boundary}\nContent-Type: {$ctype};\n name=\"{$basename}\";\nContent-Transfer-Encoding: base64\nContent-Disposition: {$disposition};\n filename=\"{$basename}\"\n"; $ata[$k++] = $subhdr; $linesz= filesize( $filename)+1; $fp= fopen( $filename, 'r' ); $ata[$k++] = chunk_split(base64_encode(fread( $fp, $linesz))); fclose($fp); } $fullBody .= implode($sep, $ata); } else { $fullBody = $message; } reset($this->xheaders); while( list( $hdr,$value ) = each( $this->xheaders)) { $headers .= "$hdr: $value\n"; } return $this->mail($to,$subject,$fullBody,$headers); } function Attach($filename,$filetype = "",$disposition = "inline") { if( $filetype == "" ) { $filetype = "application/x-unknown-content-type"; } $this->aattach[] = $filename; $this->actype[] = $filetype; $this->adispo[] = $disposition; } function Content_type($contenttype) { $this->content_type=$contenttype; } function Priority($priority) { if(!intval($priority))return false; if(!isset($this->priorities[$priority-1]))return false; $this->xheaders["X-Priority"] = $this->priorities[$priority-1]; return true; } } ?>