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程序设计有所帮助。