PHP实现支持SSL连接的SMTP邮件发送类
本文实例讲述了PHP实现支持SSL连接的SMTP邮件发送类。分享给大家供大家参考。具体如下:
该实例代码测试过了gmail和QQ邮箱的SMTP。具体代码如下:
<?php /** *邮件发送类 *支持发送纯文本邮件和HTML格式的邮件,可以多收件人,多抄送,多秘密抄送,带附件(单个或多个附件),支持到服务器的ssl连接 *需要的php扩展:sockets、Fileinfo和openssl。 *编码格式是UTF-8,传输编码格式是base64 *@example *$mail=newMySendMail(); *$mail->setServer("smtp@126.com","XXXXX@126.com","XXXXX");//设置smtp服务器,普通连接方式 *$mail->setServer("smtp.gmail.com","XXXXX@gmail.com","XXXXX",465,true);//设置smtp服务器,到服务器的SSL连接 *$mail->setFrom("XXXXX");//设置发件人 *$mail->setReceiver("XXXXX");//设置收件人,多个收件人,调用多次 *$mail->setCc("XXXX");//设置抄送,多个抄送,调用多次 *$mail->setBcc("XXXXX");//设置秘密抄送,多个秘密抄送,调用多次 *$mail->addAttachment("XXXX");//添加附件,多个附件,调用多次 *$mail->setMail("test","<b>test</b>");//设置邮件主题、内容 *$mail->sendMail();//发送 */ classMySendMail{ /** *@varstring邮件传输代理用户名 *@accessprotected */ protected$_userName; /** *@varstring邮件传输代理密码 *@accessprotected */ protected$_password; /** *@varstring邮件传输代理服务器地址 *@accessprotected */ protected$_sendServer; /** *@varint邮件传输代理服务器端口 *@accessprotected */ protected$_port; /** *@varstring发件人 *@accessprotected */ protected$_from; /** *@vararray收件人 *@accessprotected */ protected$_to=array(); /** *@vararray抄送 *@accessprotected */ protected$_cc=array(); /** *@vararray秘密抄送 *@accessprotected */ protected$_bcc=array(); /** *@varstring主题 *@accessprotected */ protected$_subject; /** *@varstring邮件正文 *@accessprotected */ protected$_body; /** *@vararray附件 *@accessprotected */ protected$_attachment=array(); /** *@varreourcesocket资源 *@accessprotected */ protected$_socket; /** *@varreource是否是安全连接 *@accessprotected */ protected$_isSecurity; /** *@varstring错误信息 *@accessprotected */ protected$_errorMessage; /** *设置邮件传输代理,如果是可以匿名发送有邮件的服务器,只需传递代理服务器地址就行 *@accesspublic *@paramstring$server代理服务器的ip或者域名 *@paramstring$username认证账号 *@paramstring$password认证密码 *@paramint$port代理服务器的端口,smtp默认25号端口 *@paramboolean$isSecurity到服务器的连接是否为安全连接,默认false *@returnboolean */ publicfunctionsetServer($server,$username="",$password="",$port=25,$isSecurity=false){ $this->_sendServer=$server; $this->_port=$port; $this->_isSecurity=$isSecurity; $this->_userName=empty($username)?"":base64_encode($username); $this->_password=empty($password)?"":base64_encode($password); returntrue; } /** *设置发件人 *@accesspublic *@paramstring$from发件人地址 *@returnboolean */ publicfunctionsetFrom($from){ $this->_from=$from; returntrue; } /** *设置收件人,多个收件人,调用多次. *@accesspublic *@paramstring$to收件人地址 *@returnboolean */ publicfunctionsetReceiver($to){ $this->_to[]=$to; returntrue; } /** *设置抄送,多个抄送,调用多次. *@accesspublic *@paramstring$cc抄送地址 *@returnboolean */ publicfunctionsetCc($cc){ $this->_cc[]=$cc; returntrue; } /** *设置秘密抄送,多个秘密抄送,调用多次 *@accesspublic *@paramstring$bcc秘密抄送地址 *@returnboolean */ publicfunctionsetBcc($bcc){ $this->_bcc[]=$bcc; returntrue; } /** *设置邮件附件,多个附件,调用多次 *@accesspublic *@paramstring$file文件地址 *@returnboolean */ publicfunctionaddAttachment($file){ if(!file_exists($file)){ $this->_errorMessage="file".$file."doesnotexist."; returnfalse; } $this->_attachment[]=$file; returntrue; } /** *设置邮件信息 *@accesspublic *@paramstring$body邮件主题 *@paramstring$subject邮件主体内容,可以是纯文本,也可是是HTML文本 *@returnboolean */ publicfunctionsetMail($subject,$body){ $this->_subject=base64_encode($subject); $this->_body=base64_encode($body); returntrue; } /** *发送邮件 *@accesspublic *@returnboolean */ publicfunctionsendMail(){ $command=$this->getCommand(); $this->_isSecurity?$this->socketSecurity():$this->socket(); foreach($commandas$value){ $result=$this->_isSecurity?$this->sendCommandSecurity($value[0],$value[1]):$this->sendCommand($value[0],$value[1]); if($result){ continue; } else{ returnfalse; } } //其实这里也没必要关闭,smtp命令:QUIT发出之后,服务器就关闭了连接,本地的socket资源会自动释放 $this->_isSecurity?$this->closeSecutity():$this->close(); returntrue; } /** *返回错误信息 *@returnstring */ publicfunctionerror(){ if(!isset($this->_errorMessage)){ $this->_errorMessage=""; } return$this->_errorMessage; } /** *返回mail命令 *@accessprotected *@returnarray */ protectedfunctiongetCommand(){ $separator="----=_Part_".md5($this->_from.time()).uniqid();//分隔符 $command=array( array("HELOsendmail\r\n",250) ); if(!empty($this->_userName)){ $command[]=array("AUTHLOGIN\r\n",334); $command[]=array($this->_userName."\r\n",334); $command[]=array($this->_password."\r\n",235); } //设置发件人 $command[]=array("MAILFROM:<".$this->_from.">\r\n",250); $header="FROM:<".$this->_from.">\r\n"; //设置收件人 if(!empty($this->_to)){ $count=count($this->_to); if($count==1){ $command[]=array("RCPTTO:<".$this->_to[0].">\r\n",250); $header.="TO:<".$this->_to[0].">\r\n"; } else{ for($i=0;$i<$count;$i++){ $command[]=array("RCPTTO:<".$this->_to[$i].">\r\n",250); if($i==0){ $header.="TO:<".$this->_to[$i].">"; } elseif($i+1==$count){ $header.=",<".$this->_to[$i].">\r\n"; } else{ $header.=",<".$this->_to[$i].">"; } } } } //设置抄送 if(!empty($this->_cc)){ $count=count($this->_cc); if($count==1){ $command[]=array("RCPTTO:<".$this->_cc[0].">\r\n",250); $header.="CC:<".$this->_cc[0].">\r\n"; } else{ for($i=0;$i<$count;$i++){ $command[]=array("RCPTTO:<".$this->_cc[$i].">\r\n",250); if($i==0){ $header.="CC:<".$this->_cc[$i].">"; } elseif($i+1==$count){ $header.=",<".$this->_cc[$i].">\r\n"; } else{ $header.=",<".$this->_cc[$i].">"; } } } } //设置秘密抄送 if(!empty($this->_bcc)){ $count=count($this->_bcc); if($count==1){ $command[]=array("RCPTTO:<".$this->_bcc[0].">\r\n",250); $header.="BCC:<".$this->_bcc[0].">\r\n"; } else{ for($i=0;$i<$count;$i++){ $command[]=array("RCPTTO:<".$this->_bcc[$i].">\r\n",250); if($i==0){ $header.="BCC:<".$this->_bcc[$i].">"; } elseif($i+1==$count){ $header.=",<".$this->_bcc[$i].">\r\n"; } else{ $header.=",<".$this->_bcc[$i].">"; } } } } //主题 $header.="Subject:=?UTF-8?B?".$this->_subject."?=\r\n"; if(isset($this->_attachment)){ //含有附件的邮件头需要声明成这个 $header.="Content-Type:multipart/mixed;\r\n"; } elseif(false){ //邮件体含有图片资源的,且包含的图片在邮件内部时声明成这个,如果是引用的远程图片,就不需要了 $header.="Content-Type:multipart/related;\r\n"; } else{ //html或者纯文本的邮件声明成这个 $header.="Content-Type:multipart/alternative;\r\n"; } //邮件头分隔符 $header.="\t".'boundary="'.$separator.'"'; $header.="\r\nMIME-Version:1.0\r\n"; //这里开始是邮件的body部分,body部分分成几段发送 $header.="\r\n--".$separator."\r\n"; $header.="Content-Type:text/html;charset=utf-8\r\n"; $header.="Content-Transfer-Encoding:base64\r\n\r\n"; $header.=$this->_body."\r\n"; $header.="--".$separator."\r\n"; //加入附件 if(!empty($this->_attachment)){ $count=count($this->_attachment); for($i=0;$i<$count;$i++){ $header.="\r\n--".$separator."\r\n"; $header.="Content-Type:".$this->getMIMEType($this->_attachment[$i]).';name="=?UTF-8?B?'.base64_encode(basename($this->_attachment[$i])).'?="'."\r\n"; $header.="Content-Transfer-Encoding:base64\r\n"; $header.='Content-Disposition:attachment;filename="=?UTF-8?B?'.base64_encode(basename($this->_attachment[$i])).'?="'."\r\n"; $header.="\r\n"; $header.=$this->readFile($this->_attachment[$i]); $header.="\r\n--".$separator."\r\n"; } } //结束邮件数据发送 $header.="\r\n.\r\n"; $command[]=array("DATA\r\n",354); $command[]=array($header,250); $command[]=array("QUIT\r\n",221); return$command; } /** *发送命令 *@accessprotected *@paramstring$command发送到服务器的smtp命令 *@paramint$code期望服务器返回的响应吗 *@returnboolean */ protectedfunctionsendCommand($command,$code){ echo'Sendcommand:'.$command.',expectedcode:'.$code.'<br/>'; //发送命令给服务器 try{ if(socket_write($this->_socket,$command,strlen($command))){ //当邮件内容分多次发送时,没有$code,服务器没有返回 if(empty($code)) { returntrue; } //读取服务器返回 $data=trim(socket_read($this->_socket,1024)); echo'response:'.$data.'<br/><br/>'; if($data){ $pattern="/^".$code."+?/"; if(preg_match($pattern,$data)){ returntrue; } else{ $this->_errorMessage="Error:".$data."|**|command:"; returnfalse; } } else{ $this->_errorMessage="Error:".socket_strerror(socket_last_error()); returnfalse; } } else{ $this->_errorMessage="Error:".socket_strerror(socket_last_error()); returnfalse; } }catch(Exception$e){ $this->_errorMessage="Error:".$e->getMessage(); } } /** *安全连接发送命令 *@accessprotected *@paramstring$command发送到服务器的smtp命令 *@paramint$code期望服务器返回的响应吗 *@returnboolean */ protectedfunctionsendCommandSecurity($command,$code){ echo'Sendcommand:'.$command.',expectedcode:'.$code.'<br/>'; try{ if(fwrite($this->_socket,$command)){ //当邮件内容分多次发送时,没有$code,服务器没有返回 if(empty($code)) { returntrue; } //读取服务器返回 $data=trim(fread($this->_socket,1024)); echo'response:'.$data.'<br/><br/>'; if($data){ $pattern="/^".$code."+?/"; if(preg_match($pattern,$data)){ returntrue; } else{ $this->_errorMessage="Error:".$data."|**|command:"; returnfalse; } } else{ returnfalse; } } else{ $this->_errorMessage="Error:".$command."sendfailed"; returnfalse; } }catch(Exception$e){ $this->_errorMessage="Error:".$e->getMessage(); } } /** *读取附件文件内容,返回base64编码后的文件内容 *@accessprotected *@paramstring$file文件 *@returnmixed */ protectedfunctionreadFile($file){ if(file_exists($file)){ $file_obj=file_get_contents($file); returnbase64_encode($file_obj); } else{ $this->_errorMessage="file".$file."dosenotexist"; returnfalse; } } /** *获取附件MIME类型 *@accessprotected *@paramstring$file文件 *@returnmixed */ protectedfunctiongetMIMEType($file){ if(file_exists($file)){ $mime=mime_content_type($file); /*if(!preg_match("/gif|jpg|png|jpeg/",$mime)){ $mime="application/octet-stream"; }*/ return$mime; } else{ returnfalse; } } /** *建立到服务器的网络连接 *@accessprotected *@returnboolean */ protectedfunctionsocket(){ //创建socket资源 $this->_socket=socket_create(AF_INET,SOCK_STREAM,getprotobyname('tcp')); if(!$this->_socket){ $this->_errorMessage=socket_strerror(socket_last_error()); returnfalse; } socket_set_block($this->_socket);//设置阻塞模式 //连接服务器 if(!socket_connect($this->_socket,$this->_sendServer,$this->_port)){ $this->_errorMessage=socket_strerror(socket_last_error()); returnfalse; } $str=socket_read($this->_socket,1024); if(!preg_match("/220+?/",$str)){ $this->_errorMessage=$str; returnfalse; } returntrue; } /** *建立到服务器的SSL网络连接 *@accessprotected *@returnboolean */ protectedfunctionsocketSecurity(){ $remoteAddr="tcp://".$this->_sendServer.":".$this->_port; $this->_socket=stream_socket_client($remoteAddr,$errno,$errstr,30); if(!$this->_socket){ $this->_errorMessage=$errstr; returnfalse; } //设置加密连接,默认是ssl,如果需要tls连接,可以查看php手册stream_socket_enable_crypto函数的解释 stream_socket_enable_crypto($this->_socket,true,STREAM_CRYPTO_METHOD_SSLv23_CLIENT); stream_set_blocking($this->_socket,1);//设置阻塞模式 $str=fread($this->_socket,1024); if(!preg_match("/220+?/",$str)){ $this->_errorMessage=$str; returnfalse; } returntrue; } /** *关闭socket *@accessprotected *@returnboolean */ protectedfunctionclose(){ if(isset($this->_socket)&&is_object($this->_socket)){ $this->_socket->close(); returntrue; } $this->_errorMessage="Noresourcecantobeclose"; returnfalse; } /** *关闭安全socket *@accessprotected *@returnboolean */ protectedfunctioncloseSecutity(){ if(isset($this->_socket)&&is_object($this->_socket)){ stream_socket_shutdown($this->_socket,STREAM_SHUT_WR); returntrue; } $this->_errorMessage="Noresourcecantobeclose"; returnfalse; } }
希望本文所述对大家的php程序设计有所帮助。