php下使用SMTP发邮件的代码
2018-09-07 19:05
最近一个项目需要用到SMTP发送邮件,之前的库类不存在了,又不喜欢安装pear或者使用pear的net/smtp类,感觉太复杂了。就直接从discuz中抽取出核心稍微修改了下。
从协议分析网上,查找到SMTP协议的命令和应答,SMTP协议在发送SMTP和接收SMTP之间的会话是靠发送SMTP的SMTP命令和接收SMTP反馈的应答来完成的。常用的命令如下:
HELLO<domain><CRLF>识别发送方到接收SMTP的一个HELLO命令
MAILFROM:<reverse-path><CRLF><reverse-path>为发送者地址。此命令告诉接收方一个新邮件发送的开始,并对所有的状态和缓冲区进行初始化。此命令开始一个邮件传输处理,最终完成将邮件数据传送到一个或多个邮箱中。
RCPTTO:<forward-path><CRLF><forward-path>标识各个邮件接收者的地址
DATA<CRLF>
接收SMTP将把其后的行为看作邮件数据去处理,以<CRLF>.<CRLF>标识数据的结尾。
REST<CRLF>退出/复位当前的邮件传输
NOOP<CRLF>要求接收SMTP仅做OK应答。(用于测试)
QUIT<CRLF>要求接收SMTP返回一个OK应答并关闭传输。
VRFY<string><CRLF>验证指定的邮箱是否存在,由于安全因素,服务器多禁止此命令。
EXPN<string><CRLF>验证给定的邮箱列表是否存在,扩充邮箱列表,也常禁止使用。
HELP<CRLF>查询服务器支持什么命令
注:<CRLF>为回车、换行,ASCII码分别为13、10(十进制)。
另外,可以在command下,使用telnet来进行简单的手工使用SMTP。
比如:
Trying211.150.96.25...
Connectedtosmtp.263.net.
Escapecharacteris^].
220WelcometocoremailSystem(WithAnti-Spam)2.1for263(040326)
HELOweiqiong@cctk.net
250smtp.263.net
mailfrom:weiqiong@cctk.net
250Ok
rcptto:g2_t1@263.net
250Ok
data
354Enddatawith<CR><LF>.<CR><LF>
haha
.
250Ok:queuedasB9E452FF3E
quit
221Bye
Connectionclosedbyforeignhost.
在此基础上就可以写出一个简单的SMTP类了。
<?
classstmp{
private$mailcfg=array();
private$error_msg=;
function__construct($mailcfg){
$this->mailcfg=$mailcfg;
}
publicfunctionsend($mail){
$mailcfg=$this->mailcfg;
if(!$fp=fsockopen($mailcfg[server],$mailcfg[port],$errno,$errstr,30)){
return$this->error(($mailcfg[server]:$mailcfg[port])CONNECT-UnabletoconnecttotheSMTPserver,pleasecheckyour\mail_config.php\.);
}
stream_set_blocking($fp,true);
$lastmessage=fgets($fp,512);
if(substr($lastmessage,0,3)!=220){
return$this->error($mailcfg[server]:$mailcfg[port]CONNECT-$lastmessage);
}
fputs($fp,($mailcfg[auth]?EHLO:HELO)..$mailcfg[auth_username].\r\n);
$lastmessage=fgets($fp,512);
if(substr($lastmessage,0,3)!=220&&substr($lastmessage,0,3)!=250){
return$this->error(($mailcfg[server]:$mailcfg[port])HELO/EHLO-$lastmessage);
}
while(1){
if(substr($lastmessage,3,1)!=-empty($lastmessage)){
break;
}
$lastmessage=fgets($fp,512);
}
if($mailcfg[auth]){
fputs($fp,AUTHLOGIN\r\n);
$lastmessage=fgets($fp,512);
if(substr($lastmessage,0,3)!=334){
return$this->error(($mailcfg[server]:$mailcfg[port])AUTHLOGIN-$lastmessage);
}
fputs($fp,base64_encode($mailcfg[auth_username]).\r\n);
$lastmessage=fgets($fp,512);
if(substr($lastmessage,0,3)!=334){
return$this->error(($mailcfg[server]:$mailcfg[port])USERNAME-$lastmessage);
}
fputs($fp,base64_encode($mailcfg[auth_password]).\r\n);
$lastmessage=fgets($fp,512);
if(substr($lastmessage,0,3)!=235){
return$this->error(($mailcfg[server]:$mailcfg[port])PASSWORD-$lastmessage);
}
$email_from=$mailcfg[from];
}
fputs($fp,MAILFROM:<.preg_replace(/.*\<(.+?)\>.*/,\\1,$email_from).>\r\n);
$lastmessage=fgets($fp,512);
if(substr($lastmessage,0,3)!=250){
fputs($fp,MAILFROM:<.preg_replace(/.*\<(.+?)\>.*/,\\1,$email_from).>\r\n);
$lastmessage=fgets($fp,512);
if(substr($lastmessage,0,3)!=250){
return$this->error(($mailcfg[server]:$mailcfg[port])MAILFROM-$lastmessage);
}
}
$email_to=$mail[to];
foreach(explode(,,$email_to)as$touser){
$touser=trim($touser);
if($touser){
fputs($fp,RCPTTO:<$touser>\r\n);
$lastmessage=fgets($fp,512);
if(substr($lastmessage,0,3)!=250){
fputs($fp,RCPTTO:<$touser>\r\n);
$lastmessage=fgets($fp,512);
return$this->error(($mailcfg[server]:$mailcfg[port])RCPTTO-$lastmessage);
}
}
}
fputs($fp,DATA\r\n);
$lastmessage=fgets($fp,512);
if(substr($lastmessage,0,3)!=354){
return$this->error(($mailcfg[server]:$mailcfg[port])DATA-$lastmessage);
}
$str=To:$email_to\r\nFrom:$email_from\r\nSubject:.$mail[subject].\r\n\r\n.$mail[content].\r\n.\r\n;
fputs($fp,$str);
fputs($fp,QUIT\r\n);
returntrue;
}
publicfunctionget_error(){
return$this->error_msg;
}
privatefunctionerror($msg){
$this->error_msg.=$msg;
returnfalse;
}
}
?>
简单的调用例子:
<?
$mailcfg[port]=25;
$mailcfg[auth]=1;
$mailcfg[auth_username]=test;
$mailcfg[auth_password]=password;
$stmp=newstmp($mailcfg);
$mail=array(to=>test@gmail.com,subject=>测试标题,content=>邮件内容<ahref=面向对象</a>);
if(!$stmp->send($mail)){
echo$stmp->get_error();
}else{
echomailsucc!;
}
?>
如果发送成功,你就可以去邮箱查看邮件了。^_^