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()函数的第一个参数应该是用户的电子邮件地址,第二个参数是邮件标题,而第三个参数是邮件正文。

这样就完成了邮件列表应用程序的构建。