用Socket发送电子邮件
http://pythonrecord.51.net/bin/content.php3?src=1&url=doc2000082201用Socket发送电子邮件--续篇
http://pythonrecord.51.net/bin/content.php3?src=1&url=doc2001030101希望这两篇文章对你有帮助,其中“用Socket发送电子邮件--续篇”介绍了如何在有认证功能的smtp服务上发邮件。
http://pythonrecord.51.net/bin/content.php3?src=1&url=doc2000082201用Socket发送电子邮件--续篇
http://pythonrecord.51.net/bin/content.php3?src=1&url=doc2001030101希望这两篇文章对你有帮助,其中“用Socket发送电子邮件--续篇”介绍了如何在有认证功能的smtp服务上发邮件。
解决方案 »
- 求一正则写法
- 求助XAMPP架设网站开启register_globals的问题
- 一个function 传进来一个参数 里面执行了一个insert语句 但是 数据库里却有两条记录怎么回事
- 会XSL的进..用的MYSQL数据库~!在线等!!!
- 谁有“http协议详解”的东西啊
- PHP连接怎么样 SQL server2000
- 请问有人用过 PHP5 中 GD 支持 GIF 吗?
- 这是我的安装PHP、MYSQL、APACHE的总结给大家参考一下
- 熟悉页面传递变量的朋友请进!!!!!!更欢迎高手!!!!!
- 各位,我始终不明白为什么在PHP,JSP里面,有了SESSION,还要用COOKIE?
- 那位兄弟帮我看看我的源程序错在哪里?
- "Warning: _oci_open_server: ORA-12154: TNS:无法处理服务名 "可能是什么原因引起的
不过有没有别的方法了呀,简洁一些的
发现wsrboy(wsrboy) ( ) 信誉:100 好像很强
那么麻烦帮个忙把
让我能把这个贴子结掉把
按照上面说的方法我试了一下,有点问题
里面有个成员函数如下
function do_command($command, $code)
{
$this->lastact=$command;
$this->show_debug($this->lastact, "out");
fputs ( $this->fp, $this->lastact );
while(true)
{
$this->lastmessage=fgets($this->fp,512);
$this->show_debug($this->lastmessage, "in");
if(($this->lastmessage[3]==' ') or (empty($this->lastmessage)))
break;
}
......
我调试了一下,发现在调用do_command函数,执行$this->lastmessage=fgets($this->fp,512);这句时,一直执行不下去,也就是说,无法从服务器返回消息。而我在telnet方式下,响应是正确的。而其他参数,我也echo出来看过了,都是正确的。
不知道哪位大虾用过,知道这是怎么回事?先谢了ps:只要能解决,要多少分都无所谓。:)
不过不是太完善,凑合用着吧...可以满足一般要求的了...
我在新网的smtp上试过可以的.=============inc/smtp_mail.class.php=================
//这个是用来发smtp邮件的类
//需要和另一个邮件编码类一起使用.
<?php
class smtp_mail{
var $fp=false;
var $lastmsg="";
var $authMode=false;
var $debugMode=false;
var $authLoginName;
var $authLoginPassword; function read_line(){
$ret=false;
$line=fgets($this->fp,1024);
if($this->debugMode){
echo "RESPONSE: $line <br>";
}
if(ereg("^([0-9]+).(.*)$",$line,$data)){
$recv_code=$data[1];
$recv_msg=$data[2];
$ret=array($recv_code,$recv_msg);
}
return $ret;
} function dialogue($code,$cmd){
$ret=true;
if($this->debugMode){
echo "CWD: $cmd <br>";
}
fwrite($this->fp,$cmd."\r\n");
$line=$this->read_line($this->fp);
if($line==false){
$ret=false;
$this->lastmsg="";
}
else{
$this->lastmsg="$line[0] $line[1]";
if($line[0]!=$code){
$ret=false;
}
return $ret;
}
} function error_message(){
echo "SMTP Protocol failure (".$this->lastmsg.").<br>";
} function crlf_encode($data){
$data.="\n";
$data=str_replace("\n","\r\n",str_replace("\r","",$data));
$data=str_replace("\n.\r\n","\n. \r\n",$data);
return $data;
} function handle_email($from,$to,$data){
$rcpts=explode(",",$to);
$err=false;
if(!$this->dialogue(250,"HELO")){
$err=true;
}
if($this->authMode){
if(!$this->dialogue(334,"AUTH LOGIN")) {
$err=true;
}
if(!$this->dialogue(334,base64_encode($this->authLoginName))){
$err=true;
}
if(!$this->dialogue(235,base64_encode($this->authLoginPassword))){
$err=true;
}
}
if(!$this->dialogue(250,"MAIL FROM: $from") ){
$err=true;
}
for($i=0;!$err&&$i<count($rcpts);$i++){
if(!$this->dialogue(250,"RCPT TO: $rcpts[$i]")){
$err=true;
}
}
if($err||!$this->dialogue(354,"DATA")||!fwrite($this->fp,$data)||!$this->dialogue(250,"\r\n.")||!$this->dialogue(221,"QUIT") ){
$err=true;
}
if($err){
$this->error_message();
}
return !$err;
} function connect($hostname){
if($this->debugMode){
echo "CONNECTING $hostname ...";
}
$ret=false;
$this->fp=fsockopen($hostname,25);
if($this->fp){
$ret=true;
if($this->debugMode){
echo "Succeed!<br>";
}
}
else{
if($this->debugMode){
echo "Failed!<br>";
}
}
return $ret;
} function send_email($hostname,$from,$to,$data,$crlf_encode=1){
if(!$this->connect($hostname)){
echo "cannot open connection!<br>\n";
return false;
}
$line=$this->read_line();
$ret=false;
if($line&&$line[0]=="220"){
if($crlf_encode){
$data=$this->crlf_encode($data);
}
$ret=$this->handle_email($from,$to,$data);
}
else{
$this->error_message();
}
fclose($this->fp);
return $ret;
}
};
?>=================inc/text_mail.class.php==========
//这个是把邮件编码的类.
//这个类没有对邮件进行任何编码,只是普通的text_mail,把邮件头等东西加上去而已.
<?php
class text_mail{
var $reply;
var $to;
var $from;
var $subject;
var $body; function text_mail(){
$this->to="";
$this->from="";
$this->subject="";
$this->body="";
$this->reply="";
} function get_mail(){
$mail="From: $this->from \r\n";
$mail.="Reply-To: $this->reply \r\n";
$mail.="To: $this->to \r\n";
$mail.="Subject: $this->subject \r\n";
$mail.="Mime-verson:1.0 \r\n";
$mail.="Content-Type: text/plain;charset=\"GB2312\"\r\n";
$mail.="Content-Transfer-Encoding: 8bit\r\n";
$mail.="\r\n";
$mail.=str_replace("\n.\r\n","\n. \r\n",$this->body);
return $mail;
}
};
?>=================== testmail.php =====================
//测试用的文件
<?php
//include "inc/mime_mail.php"; 这个类是把邮件进行mime编码的
include "inc/text_mail.php";
include "inc/smtp_mail.php";$smtp_server="mail.eccreation.com"; //smtp地址
$from="[email protected]"; // 发信人地址
$to="[email protected]"; // 收信人地址
$subject="test!!!!!"; //题目
$body="test only!
fdsafsdajfkljdklsfsda
fds
fdsaf
dsfsdafds
f"; //内容$mail=new text_mail; //初始化编码类库
$mail->from=$from;
$mail->to=$to;
$mail->subject=$subject;
$mail->body=$body;
$mail->reply=$from;
$data=$mail->get_mail(); //返回编码邮件信体.
$smtp=new smtp_mail; //初始化邮件发送类库
$smtp->authMode=true; //需要smtp验证,把验证模式打开
$smtp->authLoginName="xxxxxxx"; // 验证用户名
$smtp->authLoginPassword="*******"; //验证密码
$smtp->send_email($smtp_server,$from,$to,$data); //发送邮件
?>
我这里的情况是这样的,用来发信的这个信箱必须是公司里的一个信箱,而公司的smtp是要验证的,所以to bamboo789(Bamboo):没关系,你说的SOCKed功能是在php.ini中的哪一项配置?我怎么找不到?to pcdreama(峰幻):谢了,我试试看
我试了一下,还是有点问题,首先,这句写的不对,
if(!$this->dialogue(250,"HELO")),应该是
if(!$this->dialogue(250,"EHLO")),否则的话,是无法使用 AUTH LOGIN 命令的。然后,在这句中
if(!$this->dialogue(334,"AUTH LOGIN")) {
$err=true;
}
调用dialogue的结果,服务器返回的不是期望的 334 VXNlcm5hbWU6
而是 250-TURN
请问知道这是怎么回事吗?
我试了一下,还是有点问题,首先,这句写的不对,
if(!$this->dialogue(250,"HELO")),应该是
if(!$this->dialogue(250,"EHLO")),否则的话,是无法使用 AUTH LOGIN 命令的。然后,在这句中
if(!$this->dialogue(334,"AUTH LOGIN")) {
$err=true;
}
调用dialogue的结果,服务器返回的不是期望的 334 VXNlcm5hbWU6
而是 250-TURN
请问知道这是怎么回事吗?
在你的服务器不行,可能是协议有些不正确吧.因为服务器的验证有很多种.
我这里的这种是使用base64对帐号密码编码,AUTH LOGIN后返回的
334 VXNlcm5hbWU6是user的意思,然后下面那个是提示输入password.
第一行那里,如果协议用EHLO我记得就不能正确运行了...这个我也觉得奇怪
根据协议,应该连接后,首先用ehlo列出可以用的协议,然后根据这些协议再选择某个连接方法.但是我用这些fgets这类函数只能取得一行反馈信息.而用freads这类函数则不能使用.所以我这个类只好只使用AUTH LOGIN的方法咯.
你可以自己用telnet模拟一下协议的过程,然后根据你那台服务器的特点修改一下我的程序就ok了.以下是结果:
CONNECTING mail.eccreation.com ...Succeed!
RESPONSE: 220 mail-g1.chinadns.com ESMTP
CWD: HELO
RESPONSE: 250 mail-g1.chinadns.com
CWD: AUTH LOGIN
RESPONSE: 334 VXNlcm5hbWU6
CWD: cGNkcmVhb*********VhdGlvbi5jb20=
RESPONSE: 334 UGFzc3dvcmQ6
CWD: bm******
RESPONSE: 235 go ahead
CWD: MAIL FROM: [email protected]
RESPONSE: 250 ok
CWD: RCPT TO: [email protected]
RESPONSE: 250 ok
CWD: DATA
RESPONSE: 354 go ahead
CWD: .
RESPONSE: 250 ok 1026447969 qp 30124
CWD: QUIT
RESPONSE: 221 mail-g1.chinadns.com
奇怪就奇怪在这里
奇怪就奇怪在这里
而在PHP中,输入 AUTH LOGIN 之后,服务器返回了 250-TURN
而不是编码过的 username: ,根本不让我继续,我倒!
还有把反馈信息贴出来研究研究~~
【CWD】: HELO
RESPONSE: 250 hsexchange.hs.handsome.com.cn Hello [192.168.60.13]
【CWD】: AUTH LOGIN
RESPONSE: 503 5.5.2 Send hello first.
--- Failed here !!!
【CWD】: Y2hlbmp4
RESPONSE: 500 5.3.3 Unrecognized command
--- Failed here !!!
如果使用HELO握手,那么在发送AUTH LOGIN后,服务器返回Send hello first,这显然不对,而且在发送username之后,返回Unrecognized command。
所以,应该不是使用HELO。如果使用EHLO,结果如下:
【CWD】: EHLO
RESPONSE: 250-hsexchange.hs.handsome.com.cn Hello [192.168.60.13]
【CWD】: AUTH LOGIN
RESPONSE: 250-TURN
--- Failed here !!!
【CWD】: Y2hlbmp4
RESPONSE: 250-ATRN
--- Failed here !!!
【CWD】: d2****p5
RESPONSE: 250-SIZE 10240000
--- Failed here !!!第3、4行我希望看到的是
【CWD】: AUTH LOGIN
RESPONSE: 334-VXNlcm5hbWU6
可它却是 250-TURN,不解
验证id: [email protected] (记住加后面@xxxxxx.xxx那部分)
验证pw: test
你可以用这个帐号测试一下.
你那个服务器能不能开个测试帐号来调试一下?
我也想知道为啥会这样.
smtp服务器是这样的么:mail.eccreation.com我这里的测试账号:
username: test
password: 123456
127.allow,RELAYCLIENT=""
这样你在本地计算机上运行mail就不需要验证了
好啊,参考一下,mailto:[email protected]
<?php
class smtp_mail{
var $fp=false;
var $lastmsg="";
var $authMode=false;
var $authLastLine;
var $debugMode=false;
var $authLoginName;
var $authLoginPassword; function read_line(){
$ret=false;
$line=fgets($this->fp,1024);
if($this->debugMode){
echo "RESPONSE: $line <br>";
flush();
}
if(ereg("^([0-9]+).(.*)$",$line,$data)){
$recv_code=$data[1];
$recv_msg=$data[2];
$ret=array($recv_code,$recv_msg);
}
return $ret;
} function dialogue($code,$cmd,$response=false){
$ret=true;
if($this->debugMode){
echo "CWD: $cmd <br>";
flush();
}
fwrite($this->fp,$cmd."\r\n");
$line=$this->read_line();
if($line==false){
$ret=false;
$this->lastmsg="";
}
else{
$this->lastmsg="$line[0] $line[1]";
if($line[0]!=$code){
$ret=false;
return $ret;
}
if($response!==false){
$response.="\r\n";
while($line[1]!=$response){
$line=$this->read_line();
// $this->lastmsg.="<br>$line[0] $line[1]";
if($line[0]!=$code){
$ret=false;
return $ret;
}
}
}
return $ret;
}
} function error_message(){
echo "SMTP Protocol failure (".$this->lastmsg.").<br>";
flush();
} function crlf_encode($data){
$data.="\n";
$data=str_replace("\n","\r\n",str_replace("\r","",$data));
$data=str_replace("\n.\r\n","\n. \r\n",$data);
return $data;
} function handle_email($from,$to,$data){
$rcpts=explode(",",$to);
$err=false;
if(!$this->dialogue(250,"HELO")){
$err=true;
}
if(!$this->dialogue(250,"EHLO",$this->authLastLine)){
$err=true;
}
if($this->authMode){
if(!$this->dialogue(334,"AUTH LOGIN")) {
$err=true;
}
if(!$this->dialogue(334,base64_encode($this->authLoginName))){
$err=true;
}
if(!$this->dialogue(235,base64_encode($this->authLoginPassword))){
$err=true;
}
}
if(!$this->dialogue(250,"MAIL FROM: $from") ){
$err=true;
}
for($i=0;!$err&&$i<count($rcpts);$i++){
if(!$this->dialogue(250,"RCPT TO: $rcpts[$i]")){
$err=true;
}
}
if($err||!$this->dialogue(354,"DATA")||!fwrite($this->fp,$data)||!$this->dialogue(250,"\r\n.")||!$this->dialogue(221,"QUIT") ){
$err=true;
}
if($err){
$this->error_message();
}
return !$err;
} function connect($hostname){
if($this->debugMode){
echo "CONNECTING $hostname ...";
}
$ret=false;
$this->fp=fsockopen($hostname,25);
if($this->fp){
$ret=true;
if($this->debugMode){
echo "Succeed!<br>";
flush();
}
}
else{
if($this->debugMode){
echo "Failed!<br>";
flush();
}
}
return $ret;
} function send_email($hostname,$from,$to,$data,$crlf_encode=1){
if(!$this->connect($hostname)){
echo "cannot open connection!<br>\n";
flush();
return false;
}
$line=$this->read_line();
$ret=false;
if($line&&$line[0]=="220"){
if($crlf_encode){
$data=$this->crlf_encode($data);
}
$ret=$this->handle_email($from,$to,$data);
}
else{
$this->error_message();
}
fclose($this->fp);
return $ret;
}
};
?>===================testmail.php======================
<?php
//include "inc/mime_mail.php";
set_time_limit(9999);
include "inc/text_mail.class.php";
include "inc/smtp_mail.class.php";//$smtp_server="mail.eccreation.com";
$smtp_server="mail.handsome.com.cn";
$from="[email protected]";
$to="[email protected]";
$subject="test HERE!!!!!!";
$body="test only!
fdsafsdajfkljdklsfsda
fds
fdsaf
dsfsdafds
f";$mail=new text_mail;
$mail->from=$from;
$mail->to=$to;
$mail->subject=$subject;
$mail->body=$body;
$mail->reply=$from;
$data=$mail->get_mail();
$smtp=new smtp_mail;
$smtp->debugMode=true;
$smtp->authMode=true;
$smtp->authLastLine="OK"; //ehlo命令列出的最后一行的文字
smtp->authLoginName="test";
$smtp->authLoginPassword="123456";
$smtp->send_email($smtp_server,$from,$to,$data);
?>
RESPONSE: 220 hsexchange.hs.handsome.com.cn Microsoft ESMTP MAIL Service, Version: 5.0.2195.4453 ready at Mon, 15 Jul 2002 11:20:34 +0800
CWD: HELO
RESPONSE: 250 hsexchange.hs.handsome.com.cn Hello [211.66.123.157]
CWD: EHLO
RESPONSE: 250-hsexchange.hs.handsome.com.cn Hello [211.66.123.157]
RESPONSE: 250-TURN
RESPONSE: 250-ATRN
RESPONSE: 250-SIZE 10240000
RESPONSE: 250-ETRN
RESPONSE: 250-PIPELINING
RESPONSE: 250-DSN
RESPONSE: 250-ENHANCEDSTATUSCODES
RESPONSE: 250-8bitmime
RESPONSE: 250-BINARYMIME
RESPONSE: 250-CHUNKING
RESPONSE: 250-VRFY
RESPONSE: 250-X-EXPS GSSAPI NTLM LOGIN
RESPONSE: 250-X-EXPS=LOGIN
RESPONSE: 250-AUTH GSSAPI NTLM LOGIN
RESPONSE: 250-AUTH=LOGIN
RESPONSE: 250-X-LINK2STATE
RESPONSE: 250-XEXCH50
RESPONSE: 250 OK
CWD: AUTH LOGIN
RESPONSE: 334 VXNlcm5hbWU6
CWD: dGVzdA==
RESPONSE: 334 UGFzc3dvcmQ6
CWD: MTIzNDU2
RESPONSE: 235 2.7.0 Authentication successful.
CWD: MAIL FROM: [email protected]
RESPONSE: 250 2.1.0 [email protected] OK
CWD: RCPT TO: [email protected]
RESPONSE: 250 2.1.5 [email protected]
CWD: DATA
RESPONSE: 354 Start mail input; end with .
CWD: .
RESPONSE: 250 2.6.0 Queued mail for delivery
CWD: QUIT
RESPONSE: 221 2.0.0 hsexchange.hs.handsome.com.cn Service closing transmission channel
主要的原因在于在用socket打开这些smtp,ftp的文件流,用户和server双方需要不断进行交流,这就意味着在交流过程中文件流不会出现eof,所有在程序进行协议过程中不能使用fread等靠eof判断文件结束的语句,而只能使用fgets靠判断\r\n而结束读取的函数.
在输入ehlo命令后,服务器将返回多行的可以使用的协议列表.如:
250-hsexchange.hs.handsome.com.cn Hello [211.66.123.157]
250-TURN
250-ATRN
250-SIZE 10240000
........
250-AUTH GSSAPI NTLM LOGIN
250-AUTH=LOGIN
250-X-LINK2STATE
250-XEXCH50
250 OK
因为这些行都会在文件流的缓冲里面,如果不把这些行全部读取完毕,那么在执行下一个命令后,就会得不到希望的返回码而只会继续读取文件流当前位置的下一行.这就是为什么执行了auth login之后会出现250-turn的原因.
现在我把类加了一个authLastLine的属性,判断这个服务器执行ehlo之后列表的最后一行是什么,然后把所有行缓冲读取完毕,以便继续执行下面的命令.如上服务器,最后一行输出是OK,所以要把authLastLine的值赋予"OK" ($smtp->authLastLine="OK";)
这个方法的确比较笨,因为对于不同服务器都需要先知道它执行了ehlo之后最后一行是什么(要自己telnet过去自己查出来),不够智能化.但是我也实在想不到有什么其他的函数可以用了,因为php本身的函数库就有这个限制.
这时候发送命令,服务器可能会不认当时,虽然看到在telnet和PHP下,有细小的差别,但是没有考虑太多,是我疏忽了,,,