send_mail类的实现
现在开始介绍我所编写的发送邮件类。有了上面的预备知识了,下面就是实现了。
类的成员变量
var $lastmessage; //记录最后返回的响应信息
var $lastact; //最后的动作,字符串形式
var $welcome; //用在helo后面,欢迎用户
var $debug; //是否显示调试信息
var $smtp; //smtp服务器
var $port; //smtp端口号
var $fp; //socket句柄
其中,$lastmessage和$lastact用于记录最后一次响应信息及执行的命令,当出错时,用户可以使用它们。为了测试需要,我还定义了$debug变量,当其值为true时,会在运行过程中显示一些执行信息,否则无任何输出。$fp用于保存打开后的socket句柄。
类的构造
--------------------------------------------------------------------------------
function send_mail($smtp, $welcome="", $debug=false)
{
if(empty($smtp)) die("smtp cannt be null!");
$this->smtp=$smtp;
if(empty($welcome))
{
$this->welcome=gethostbyaddr("localhost");
}
else
$this->welcome=$welcome;
$this->debug=$debug;
$this->lastmessage="";
$this->lastact="";
$this->port="25";
}
--------------------------------------------------------------------------------
这个构造函数主要完成一些初始值的判定及设置。$welcome用于helo指令中,告诉服务器用户的名字。helo指令要求为机器名,但是不用也可以。如果用户没有给出$welcome,则自动查找本地的机器名。
显示调试信息
--------------------------------------------------------------------------------
1 function show_debug($message, $inout)
2 {
3 if ($this->debug)
4 {
5 if($inout=="in") //响应信息
6 {
7 $m='<< ';
8 }
9 else
10 $m='>> ';
11 if(!ereg("/n$", $message))
12 $message .= "<br>";
13 $message=nl2br($message);
14 echo "<font color=#999999>${m}${message}</font>";
15 }
16 }
--------------------------------------------------------------------------------
这个函数用来显示调试信息。可以在$inout中指定是上传的指令还是返回的响应,如果为上传指令,则使用"out";如果为返回的响应则使用"in"。
第3行,判断是否要输出调试信息。
第5行,判断是否为响应信息,如果是,则在第7行将信息的前面加上"<< "来区别信息;否则在第10行加上">> "来区别上传指令。
第11-12行,判断信息串最后是否为换行符,如不是则加上html换行标记。第13行将所以的换行符转成html的换行标记。
第14行,输出整条信息,同时将信息颜色置为灰色以示区别。执行一个命令
--------------------------------------------------------------------------------
1 function do_command($command, $code)
2 {
3 $this->lastact=$command;
4 $this->show_debug($this->lastact, "out");
5 fputs ( $this->fp, $this->lastact );
6 $this->lastmessage = fgets ( $this->fp, 512 );
7 $this->show_debug($this->lastmessage, "in");
8 if(!ereg("^$code", $this->lastmessage))
9 {
10 return false;
11 }
12 else
13 return true;
14 }
--------------------------------------------------------------------------------
在编写socket处理部分发现,一些命令的处理很相似,如helo,mail from,rcpt to,quit,data命令,都要求根据是否显示调试信息将相关内容显示出来,同时对于返回的响应码,如果是期望的,则应继续处理,如果不是期望的,则应中断出理。所以为了清晰与简化,专门对这些命令的处理编写了一个通用处理函数。函数的参数中$code为期望的响应码,如果响应码与之相同则表示处理成功,否则出错。
第3行,记录最后执行命令。
第4行,将上传命令显示出来。
第5行,则使用fputs真正向服务器传换指令。
第6行,从服务器接收响应信息将放在最后响应消息变量中。
第7行,将响应信息显示出来。
第8行,判断响应信息是否期待的,如果是则第13行返回成功(true),否则在第10行返回失败(false)。
这样,这个函数一方面完成指令及信息的发送显示功能,别一方面对返回的响应判断是否成功。
邮件发送处理
下面是真正的秘密了,可要看仔细了。:)
--------------------------------------------------------------------------------
1 function send( $to,$from,$subject,$message)
2 {
3
4 //连接服务器
5 $this->lastact="connect";
6
7 $this->show_debug("connect to smtp server : ".$this->smtp, "out");
8 $this->fp = fsockopen ( $this->smtp, $this->port );
9 if ( $this->fp )
10 {
11
12 set_socket_blocking( $this->fp, true );
13 $this->lastmessage=fgets($this->fp,512);
14 $this->show_debug($this->lastmessage, "in");
15
16 if (! ereg ( "^220", $this->lastmessage ) )
17 {
18 return false;
19 }
20 else
21 {
22 $this->lastact="helo " . $this->welcome . "/n";
23 if(!$this->do_command($this->lastact, "250"))
24 {
25 fclose($this->fp);
26 return false;
27 }
28
29 $this->lastact="mail from: $from" . "/n";
30 if(!$this->do_command($this->lastact, "250"))
31 {
32 fclose($this->fp);
33 return false;
34 }
35
36 $this->lastact="rcpt to: $to" . "/n";
37 if(!$this->do_command($this->lastact, "250"))
38 {
39 fclose($this->fp);
40 return false;
41 }
42
43 //发送正文
44 $this->lastact="data/n";
45 if(!$this->do_command($this->lastact, "354"))
46 {
47 fclose($this->fp);
48 return false;
49 }
50
51 //处理subject头
52 $head="subject: $subject/n";
53 if(!empty($subject) && !ereg($head, $message))
54 {
55 $message = $head.$message;
56 }
57
58 //处理from头
59 $head="from: $from/n";
60 if(!empty($from) && !ereg($head, $message))
61 {
62 $message = $head.$message;
63 }
64
65 //处理to头
66 $head="to: $to/n";
67 if(!empty($to) && !ereg($head, $message))
68 {
69 $message = $head.$message;
70 }
71
72 //加上结束串
73 if(!ereg("/n/./n", $message))
74 $message .= "/n./n";
75 $this->show_debug($message, "out");
76 fputs($this->fp, $message);
77
78 $this->lastact="quit/n";
79 if(!$this->do_command($this->lastact, "250"))
80 {
81 fclose($this->fp);
82 return false;
83 }
84 }
85 return true;
86 }
87 else
88 {
89 $this->show_debug("connect failed!", "in");
90 return false;
91 }
92 }
--------------------------------------------------------------------------------
有些意思很清楚的我就不说了。
这个函数一共有四个参数,分别是$to表示收信人,$from表示发信人,$subject表求邮件主题和$message表示邮件体。如果处理成功则返回true,失败则返回false。
第8行,连接邮件服务器,如果成功响应码应为220。
第12行,设置阻塞模式,表示信息必须返回才能继续。详细说明看手册吧。
第16行,判断响应码是否为220,如果是,则继续处理,否则出错返回。
第22-27行,处理helo指令,期望响应码为250。
第29-34行,处理mail from指令,期望响应码为250。
第36-41行,处理rcpt to指令,期望响应码为250。
第44-49行,处理data指令,期望响应码为354。
第51-76行,生成邮件体,并发送。
第52-56行,如果$subject不为空,则查找邮件体中是否有主题部分,如果没有,则加上主题部分。
第59-63行,如果$from不为空,则查找邮件体中是否有发信人部分,如果没有,则加上发信人部分。
第66-70行,如果$to不为空,则查找邮件体中是否有收信人部分,如果没有,则加上收信人部分。
第73-74行,查找邮件体是否有了结束行,如果没有则加上邮件体的结束行(以"."作为单独的一行的特殊行)。
第76行,发送邮件体。
第78-83行,执行quit结否与服务器的连接,期望响应码为250。
第85行,返回处理成功标志(true)。
第81-91行,与服务器连接失败的处理。
以上为整个send_mail类的实现,应该不是很难的。
下面给出一个实例。
邮件发送实例
先给出一个最简单的实例:
<?php
1 include "sendmail.class.php3";
2 $email="hello, this is a test letter!";
3 $sendmail=new send_mail("smtp.263.net", "limodou", true); //显示调示信息
4 if($sendmail->send("[email protected]", "[email protected]", "test", $email))
5 {
6 echo "发送成功!<br>";
7 }
8 else
9 {
10 echo "发送失败!<br>";
11 }
?>
第1行,装入send_mail类。
第3行,创建一个类的实例,且设置显示调示信息,如果不想显示,可以
$sendmail=new send_mail("smtp.263.net");。
第4行,发送邮件。
很简单,不是吗?下面再给合以前的发送mime邮件的例子,给出一个发送html附件的例子。
<?php
include "mime.class.php3";
//注,在发送mime邮件一文中,这个类文件名为mime.class,在此处我改成这样的
$to = '[email protected]'; //改为收信人的邮箱
$str = "newsletter for ".date('m y', time());
//信息被我改少了
$html_data = '<html><head><title>'. $str. '</title></head>
<body bgcolor="#ffffff">
hello! this is a test!
</body>
</html>';
//生成mime类实例
$mime = new mime_mail("[email protected]", $to, $str);
//添加html附件
$mime->attach($html_data, "", html, base64);
//注释掉,采用我的发送邮件处理
//$mime->send_mail();
//生成邮件
$mime->gen_email();
//显示邮件信息
//echo $mime->email."<br>";
//包含sendmail文件
include "sendmail.class.php3";
//创建实例
$sendmail=new send_mail("smtp.263.net", "limodou", true);
//发送邮件
$sendmail->send("[email protected]", "[email protected]", $str, $mime->email);
?>
注释写的很清楚,就不再做更多的解释了。如果实际应用中,请将send_mail构造函数中的debug设为false或不写即可。
新闻热点
疑难解答