30.7.5 发送邮件
点击新闻信件的发送按钮将触发发送动作,该动作将触发如下代码:
case'send':
send($_GET['id'],$_SESSION['admin_user']);
break;
该代码将调用send()函数,该函数可以在mlm_fns.php函数库中找到。这是一个相当长的函数。它也是我们使用Mail_mime类的地方。
该函数的代码如程序清单30-17所示。
程序清单30-17 mlm_fns.php函数库中的send()函数——该函数最终将发送一个新闻信件
//create the message from the stored DB entries and files
//send test messages to the administrator,or real messages to the whole list
function send($mailid,$admin_user){
if(!check_admin_user($admin_user)){
return false;
}
if(!($info=load_mail_info($mailid))){
echo"<p>Cannot load list information for message".$mailid."</p>";
return false;
}
$subject=$info['subject'];
$listid=$info['listid'];
$status=$info['status'];
$sent=$info['sent'];
$from_name='Pyramid MLM';
$from_address='return@address';
$query="select email from sub_lists where listid='".$listid."'";
$conn=db_connect();
$result=$conn->query($query);
if(!$result){
echo$query;
return false;
}else if($result->num_rows==0){
echo"<p>There is nobody subscribed to list number".$listid."</p>";
return false;
}
//include PEAR mail classes
include('Mail.php');
include('Mail/mime.php');
//instantiate MIME class and pass it the carriage return/line feed
//character used on this system
$message=new Mail_mime("\r\n");
//read in the text version of the newsletter
$textfilename="archive/".$listid."/".$mailid."/text.txt";
$tfp=fopen($textfilename,"r");
$text=fread($tfp,filesize($textfilename));
fclose($tfp);
//read in the HTML version of the newsletter
$htmlfilename="archive/".$listid."/".$mailid."/index.html";
$hfp=fopen($htmlfilename,"r");
$html=fread($hfp,filesize($htmlfilename));
fclose($hfp);
//add HTML and text to the mimemail object
$message->setTXTBody($text);
$message->setHTMLBody($html);
//get the list of images that relate to this message
$query="select path,mimetype from images where
mailid='".$mailid."'";
$result=$conn->query($query);
if(!$result){
echo"<p>Unable to get image list from database.</p>";
return false;
}
$num=$result->num_rows;
for($i=0;$i<$num;$i++){
//load each image from disk
$row=$result->fetch_array();
$imgfilename="archive/$listid/$mailid/".$row[0];
$imgtype=$row[1];
//add each image to the object
$message->addHTMLImage($imgfilename,$imgtype,
$imgfilename,true);
}
//create message body
$body=$message->get();
//create message headers
$from='"'.get_real_name($admin_user).'"<'.$admin_user.'>';
$hdrarray=array(
'From'=>$from,
'Subject'=>$subject);
$hdrs=$message->headers($hdrarray);
//create the actual sending object
$sender=&Mail::factory('mail');
if($status=='STORED'){
//send the HTML message to the administrator
$sender->send($admin_user,$hdrs,$body);
//send the plain text version of the message to administrator
mail($admin_user,$subject,$text,
'From:"'.get_real_name($admin_user).'"<'.$admin_user.'>');
echo"Mail sent to".$admin_user."";
//mark newsletter as tested
$query="update mail set status='TESTED'where
mailid='".$mailid."'";
$result=$conn->query($query);
echo"<p>Press send again to send mail to whole list.
<div align=\"center\">";
display_button('send','&id='.$mailid);
echo"</div></p>";
}else if($status=='TESTED'){
//send to whole list
$query="select subscribers.realname,sub_lists.email,
subscribers.mimetype
from sub_lists,subscribers
where listid=$listid and
sub_lists.email=subscribers.email";
$result=$conn->query($query);
if(!$result){
echo"<p>Error getting subscriber list</p>";
}
$count=0;
//for each subscriber
while($subscriber=$result->fetch_row()){
if($subscriber[2]=='H'){
//send HTML version to people who want it
$sender->send($subscriber[1],$hdrs,$body);
}else{
//send text version to people who don't want HTML mail
mail($subscriber[1],$subject,$text,
'From:"'.get_real_name($admin_user).'"
<'.$admin_user.'>');
}
$count++;
}
$query="update mail set status='SENT',sent=now()
where mailid='".$mailid."'";
$result=$conn->query($query);
echo"<p>A total of$count messages were sent.</p>";
}else if($status=='SENT'){
echo"<p>This mail has already been sent.</p>";
}
}
该函数将完成几项不同的操作。在将新闻信件发送出去之前,该函数测试性地将它发送给管理员。它通过记录数据库中邮件的状态来保存这些信息。当上载程序脚本程序上载一封邮件时,该函数将该邮件的初始状态设置为"STORED"。
如果send()函数发现某邮件状态为"STORED",则将它更改为"TESTED"并将它发送给管理员。"TESTED"状态表示该新闻信件已经被发送并经过管理员测试了。如果send()函数遇到某邮件状态为"TESTED",则把它变成"SENT"并将它发送给列表上所有用户。这意味着每封邮件必须经过两次发送:一次是测试模式;一次是实际模式。
该函数还可以发送两种不同的邮件:通过PHP的mail()函数发送的文本版本,和用Mail_mime类发送的HTML版本。在本书中,我们已经在多处用到了mail()函数,因此在这里我们了解一下如何使用Mail_mime类。但是,我们并不会全面地讨论该类,只解释如何在这个典型的程序中使用它。
首先,我们将类文件包含进来并创建Mail_mime类的一个实例:
//include PEAR mail classes
include('Mail.php');
include('Mail/mime.php');
//instantiate MIME class and pass it the carriage return/line feed
//character used on this system
$message=new Mail_mime("\r\n");
请注意,我们在这里包含了两个类文件。我们还将使用PEAR软件包中的常规Mail类,正是这个类真正完成了邮件发送功能。这个类随同PEAR软件包一起安装。
Mail_mime类可以用来创建将要发送的MIME格式消息。
接下来,我们将读入邮件的文本和HTML版本,并且将它们添加到Mail_mime类:
//read in the text version of the newsletter
$textfilename="archive/".$listid."/".$mailid."/text.txt";
$tfp=fopen($textfilename,"r");
$text=fread($tfp,filesize($textfilename));
fclose($tfp);
//read in the HTML version of the newsletter
$htmlfilename="archive/".$listid."/".$mailid."/index.html";
$hfp=fopen($htmlfilename,"r");
$html=fread($hfp,filesize($htmlfilename));
fclose($hfp);
//add HTML and text to the mimemail object
$message->setTXTBody($text);
$message->setHTMLBody($html);
完成邮件读入后,该脚本循环地从数据库中载入每一个图片细节,并将其添加到需要发送的邮件中:
$num=$result->num_rows;
for($i=0;$i<$num;$i++){
//load each image from disk
$row=$result->fetch_array();
$imgfilename="archive/".$listid."/".$mailid."/".$row[0];
$imgtype=$row[1];
//add each image to the object
$message->addHTMLImage($imgfilename,$imgtype,$imgfilename,true);
}
在这里,传递给addHTMLImage()函数的参数分别是:图像文件的名称(或者我们可以传递图像数据)、图像的MIME类型、文件名称,以及用来标记第一个参数是图像文件名称而不是文件数据的true(如果想传递原始图像数据,可以传递数据、MIME类型、空参数和false)。这些参数有些繁琐。
在这一步,我们需要创建邮件正文。在设置邮件标题前,必须先创建邮件正文。我们按如下代码创建邮件正文:
//create message body
$body=$message->get();
接下来,可以调用Mail_mime类的headers()函数创建该邮件标题:
//create message headers
$from='"'.get_real_name($admin_user).'"<'.$admin_user.'>';
$hdrarray=array(
'From'=>$from,
'Subject'=>$subject);
最后,在设置完邮件后,就可以发送它了。在发送该邮件前,还需要初始化PEAR Mail类,并且将其传递给我们所创建的邮件。初始化该类的代码如下所示:
//create the actual sending object
$sender=&Mail::factory('mail');
(在这里,'mail'参数只是告诉Mail类使用PHP的mail()函数来发送邮件。很明显,也可以使用'sendmail'或'smtp'作为该参数值。)
接下来,我们将该邮件发送给每一个订阅者,通过检索该列表的每一个订阅者,并且根据用户的MIME类型,使用Mail的send()函数或常规的mail()函数来发送邮件:
if($subscriber[2]=='H'){
//send HTML version to people who want it
$sender->send($subscriber[1],$hdrs,$body);
}else{
//send text version to people who don't want HTML mail
mail($subscriber[1],$subject,$text,
'From:"'.get_real_name($admin_user).'"
<'.$admin_user.'>');
}
$sender->send()函数的第一个参数应该是用户的电子邮件地址,第二个参数是邮件标题,而第三个参数是邮件正文。
这样就完成了邮件列表应用程序的构建。