推荐应用
Discuz发送邮件原理问题分析
发布于 2013-01-12
这里就针对dx的发送邮件函数进行一个简单的分析,供人参考,如果说我不想看这个分析,我想查找我的问题。我不懂你说的是什么。那么请跳到二楼。
下面开始。
邮件发送常用的有2种方式
1、sendmail方式,这种方式要服务器支持,不需要提供其他。
2、socket链接smtp方式,这种方式基本上服务器都可以使用这种方式,但是需要你提供smtp服务器 用户名 密码等。
发送邮件不成功的话,去检查data/log 下的 xxx__SMTP.php文件内容XXX是本月的日期,发送邮件的过程中出现的问题,也都会以日志的方式保存在这里。这个日志里面基本上记录的都是第二种方式出现的错误。
以下并非完全分析发送邮件函数,只检出来对大家可能有用的说。
1、sendmail方式,这种方式要服务器支持,不需要提供其他。
2、socket链接smtp方式
首先用下面代码建立链接,如果失败则记录日志 XXX CONNECT - Unable to connect to the SMTP server.这个时候你就要检查你服务器与smtp服务器之间建立链接的时候出现了什么问题。
用qqmail 来举例这里得到的正常值应该是类似这样一句 220 esmtp10.qq.com Esmtp QQ Mail Server
然后再读512个字符,判断是否是220或者250.否的话则输出错误信息。
先发送 AUTH LOGIN\r\n 然后取消息,如果返回消息开头不等于334 则记录错误。
然后发送SMTP 身份验证用户名。并判断是否错误。
最后发送 SMTP 身份验证密码。并判断是否错误。
在这里顺便说一句,本人在这里使用QQ邮箱做测试。在QQ邮箱中有一项如果不设置,得到的会是 ”454 Authentication failed, please open smtp flag first! “
首先在后台设置好邮件设置
然后下载附件中的testmail.zip 解压缩。
修改里面的 testmail.php 编辑三项
$toemail = ""; #发送到XXX邮箱,填写您要发送到的邮箱。
$subject = ""; #邮件主体
$message = ""; #邮件内容
在引号之中填写信息。
把 testmail.php 上传到你网站的根目录
然后执行
例如 www.xxx.com/testmail.php
看输出的信息来判断问题。
最后解决了之后不要忘记删除这个文件。
下面开始。
邮件发送常用的有2种方式
1、sendmail方式,这种方式要服务器支持,不需要提供其他。
2、socket链接smtp方式,这种方式基本上服务器都可以使用这种方式,但是需要你提供smtp服务器 用户名 密码等。
发送邮件不成功的话,去检查data/log 下的 xxx__SMTP.php文件内容XXX是本月的日期,发送邮件的过程中出现的问题,也都会以日志的方式保存在这里。这个日志里面基本上记录的都是第二种方式出现的错误。
以下并非完全分析发送邮件函数,只检出来对大家可能有用的说。
1、sendmail方式,这种方式要服务器支持,不需要提供其他。
if(function_exists('mail') && @mail($email_to, $email_subject, $email_message, $headers)) {
return true;
}
return false;
判断mail函数是否存在和使用mail函数发信。失败则返回false。sendmail函数并不在log文件中输出错误信息。不过一般服务器sendmail没有问题的话,都能发出去了。2、socket链接smtp方式
首先用下面代码建立链接,如果失败则记录日志 XXX CONNECT - Unable to connect to the SMTP server.这个时候你就要检查你服务器与smtp服务器之间建立链接的时候出现了什么问题。
if(!$fp = fsockopen($_G['setting']['mail']['server'], $_G['setting']['mail']['port'], $errno, $errstr, 30)) {
runlog('SMTP', "({$_G[setting][mail][server]}:{$_G[setting][mail][port]}) CONNECT - Unable to connect to the SMTP server", 0);
return false;
}
下面代码从建立的连接中读取512个字符,如果读取到的前三个字符不等于220那么则输出错误信息XXX_ CONNECT xxx用qqmail 来举例这里得到的正常值应该是类似这样一句 220 esmtp10.qq.com Esmtp QQ Mail Server
$lastmessage = fgets($fp, 512);
if(substr($lastmessage, 0, 3) != '220') {
runlog('SMTP', "{$_G[setting][mail][server]}:{$_G[setting][mail][port]} CONNECT - $lastmessage", 0);
return false;
}
下面代码是向邮件服务器标示用户身份。如果后台填写smtp服务器那块勾上验证的勾,就发送 EHLO 反之,发送 HELO。然后再读512个字符,判断是否是220或者250.否的话则输出错误信息。
fputs($fp, ($_G['setting']['mail']['auth'] ? 'EHLO' : 'HELO')." uchome\r\n");
$lastmessage = fgets($fp, 512);
if(substr($lastmessage, 0, 3) != 220 && substr($lastmessage, 0, 3) != 250) {
runlog('SMTP', "({$_G[setting][mail][server]}:{$_G[setting][mail][port]}) HELO/EHLO - $lastmessage", 0);
return false;
}
while(1) {
if(substr($lastmessage, 3, 1) != '-' || empty($lastmessage)) {
break;
}
$lastmessage = fgets($fp, 512);
}
如果前面勾上需要验证的话,后面就要进行验证的步骤了先发送 AUTH LOGIN\r\n 然后取消息,如果返回消息开头不等于334 则记录错误。
然后发送SMTP 身份验证用户名。并判断是否错误。
最后发送 SMTP 身份验证密码。并判断是否错误。
在这里顺便说一句,本人在这里使用QQ邮箱做测试。在QQ邮箱中有一项如果不设置,得到的会是 ”454 Authentication failed, please open smtp flag first! “
if($_G['setting']['mail']['auth']) {
fputs($fp, "AUTH LOGIN\r\n");
$lastmessage = fgets($fp, 512);
echo "
".$lastmessage."
";
if(substr($lastmessage, 0, 3) != 334) {
runlog('SMTP', "({$_G[setting][mail][server]}:{$_G[setting][mail][port]}) AUTH LOGIN - $lastmessage", 0);
}
fputs($fp, base64_encode($_G['setting']['mail']['auth_username'])."\r\n");
$lastmessage = fgets($fp, 512);
if(substr($lastmessage, 0, 3) != 334) {
runlog('SMTP', "({$_G[setting][mail][server]}:{$_G[setting][mail][port]}) USERNAME - $lastmessage", 0);
echo "$lastmessage:".$lastmessage."
";
}
fputs($fp, base64_encode($_G['setting']['mail']['auth_password'])."\r\n");
$lastmessage = fgets($fp, 512);
if(substr($lastmessage, 0, 3) != 235) {
runlog('SMTP', "({$_G[setting][mail][server]}:{$_G[setting][mail][port]}) PASSWORD - $lastmessage", 0);
echo "e";
}
$email_from = $_G['setting']['mail']['from'];
}
后面的一起来说,前面链接成功了,验证成功了。后面就是发送邮件主体的部分了。没一步发送信息后都要对服务器返回值进行判断,如果开头不等于250 均记录错误日志并且退出。fputs($fp, "MAIL FROM: <".preg_replace("/.*\<(.+?)\>.*/", "\\1", $email_from).">\r\n");
$lastmessage = fgets($fp, 512);
if(substr($lastmessage, 0, 3) != 250) {
fputs($fp, "MAIL FROM: <".preg_replace("/.*\<(.+?)\>.*/", "\\1", $email_from).">\r\n");
$lastmessage = fgets($fp, 512);
if(substr($lastmessage, 0, 3) != 250) {
runlog('SMTP', "({$_G[setting][mail][server]}:{$_G[setting][mail][port]}) MAIL FROM - $lastmessage", 0);
return false;
}
}
fputs($fp, "RCPT TO: <".preg_replace("/.*\<(.+?)\>.*/", "\\1", $toemail).">\r\n");
$lastmessage = fgets($fp, 512);
if(substr($lastmessage, 0, 3) != 250) {
fputs($fp, "RCPT TO: <".preg_replace("/.*\<(.+?)\>.*/", "\\1", $toemail).">\r\n");
$lastmessage = fgets($fp, 512);
runlog('SMTP', "({$_G[setting][mail][server]}:{$_G[setting][mail][port]}) RCPT TO - $lastmessage", 0);
return false;
}
fputs($fp, "DATA\r\n");
$lastmessage = fgets($fp, 512);
if(substr($lastmessage, 0, 3) != 354) {
runlog('SMTP', "({$_G[setting][mail][server]}:{$_G[setting][mail][port]}) DATA - $lastmessage", 0);
return false;
}
$headers .= 'Message-ID: <'.gmdate('YmdHs').'.'.substr(md5($email_message.microtime()), 0, 6).rand(100000, 999999).'@'.$_SERVER['HTTP_HOST'].">{$maildelimiter}";
fputs($fp, "Date: ".gmdate('r')."\r\n");
fputs($fp, "To: ".$email_to."\r\n");
fputs($fp, "Subject: ".$email_subject."\r\n");
fputs($fp, $headers."\r\n");
fputs($fp, "\r\n\r\n");
fputs($fp, "$email_message\r\n.\r\n");
$lastmessage = fgets($fp, 512);
if(substr($lastmessage, 0, 3) != 250) {
runlog('SMTP', "({$_G[setting][mail][server]}:{$_G[setting][mail][port]}) END - $lastmessage", 0);
}
fputs($fp, "QUIT\r\n");
如果说我不想看上面的,我就想查找我到底是哪一步出现问题了。那么我把发送邮件函数摘出来了。并且每一步输出了文字信息在浏览器上。这样您拿着文字信息来找人帮你分析是什么错误。首先在后台设置好邮件设置
然后下载附件中的testmail.zip 解压缩。
修改里面的 testmail.php 编辑三项
$toemail = ""; #发送到XXX邮箱,填写您要发送到的邮箱。
$subject = ""; #邮件主体
$message = ""; #邮件内容
在引号之中填写信息。
把 testmail.php 上传到你网站的根目录
然后执行
例如 www.xxx.com/testmail.php
看输出的信息来判断问题。
最后解决了之后不要忘记删除这个文件。