PHP中的imap_open函数有时会看到空白的消息正文


imap_open function in PHP sometimes see blank message body

我使用PHP中的imap_open函数下载电子邮件并将其插入mysql数据库

这是我获取标题和正文消息等的代码:

$emails = imap_search($inbox,'ALL');
//if emails are returned, cycle through each...
if($emails)
{
    //begin output var
    $output = '';
    //put the newest emails on top
    rsort($emails);
    //for every email...
    foreach($emails as $email_number) 
    {
        //get information specific to this email
        $header=imap_headerinfo($inbox,$email_number);
        $structure = imap_fetchstructure($inbox,$email_number);
        $from = $header->from[0]->mailbox . "@" . $header->from[0]->host;
        $toaddress=$header->to[0]->mailbox."@".$header->to[0]->host;
        $replyto=$header->reply_to[0]->mailbox."@".$header->reply_to[0]->host;
        $datetime=date("Y-m-d H:i:s",$header->udate);
        $subject=$header->subject;
    $message = quoted_printable_decode(imap_fetchbody($inbox,$email_number,1.1)); 
    if($message == '')
    {
        $message = quoted_printable_decode(imap_fetchbody($inbox,$email_number,1));
    }
}
}

但它似乎并不是所有电子邮件的主体。例如,当它收到"已读回执"时,正文只是空白,与人们发送的其他一些电子邮件相同。

有时,电子邮件正文看起来像:

PGh0bWw+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIgY29udGVudD0i dGV4dC9odG1sOyBjaGFyc2V0pXV0Zi04Ij4NCjwvaGVhZD4 NCjxib2R5IHN0eWxlPSJ3b3JkLXdy YXA6IGJyZWFrLXdvcmQ7IC13ZWJraXQtbmJzc1tb2RlOiBzcGFjZTsgLXdlYmtpdC1saW5lLWJy ZWFr OiBhZnRlci13aGl0ZS1zcGFjZTsgY29sb3I6IHJnYigwLCAwLCAwKTsgZm9udC1zaXplOiAx NHB4OyBmb250LWZhbWlseTogQ2FsaWJyaSwgc2Fucy1zZXJpZjsiPg0KPGRpdj4NCjxkaXY+DQo8ZGl2PnJlcGx5PC9kaXY+DQo8ZGl2Pg0KPHAGC35bGU9ImZvbnQtZmFtaWx5OiBDYXPYnJpOyBt YXJnaW46IDBweCAwcHggMTJweDsiPjxiPktpbmQgUmVnYXJkcyw8YnI+DQpDaGFybGll IEZvcmQgfCZuYnNwOzvYj48c3BhbiBzdHlsZT0iY29s3I6IHJnYigyNTIsIDc5LCA4KTsipjxi PlRl Y2huaWNhbCBNYW5hZ2VyJm5ic3A7PC9iPjwvc3Bbj48Yj58Jm5IC3A7SW50ZWdyYSBEaWdp dGFsPC9iPjxmb250IGNvbG9yPSIjNTk1OTU。。。持续

如何将整个消息正文转换为纯文本

以下是我通常使用的内容。$email是指返回的对象之一,例如imap_fetch_overview:

$structure = imap_fetchstructure($email->msgno);
$body = imap_fetchbody($email->msgno, '1');
if (3 === $structure->encoding) {
    $body = imap_base64($body);
} else if (4 === $structure->encoding) {
    $body = imap_qprint($body);
}

请注意,有6种可能的编码(从0到5),我只处理其中的2种(3和4)——您可能希望处理所有编码。

还需要注意的是,我只得到了第一部分(在imap_fetchbody中)——您可能需要循环这些片段来获得它们。

更新
关于你的代码,我注意到了另一件事。你在做imap_fetchbody($inbox,$email_number,1.1)。第三个参数应该是字符串,而不是数字。改为:

imap_fetchbody($inbox, $email_number, '1.1')

给定的代码只处理最多有一个子部分且没有编码的简单文本消息。这基本上是最简单的电子邮件。世界曾经那么简单,遗憾的是,现在已经没有了!

要处理更多的电子邮件,您的代码必须扩展为处理:

  1. 多部件
  2. 编码

多部分是一个概念,即一封电子邮件(一堆数据)可以分为多个逻辑上独立的部分。在最简单的情况下,只有一部分:消息的文本。在下一个最简单的情况下,有一个带有单个附件的消息文本。下一种最简单的情况是消息文本加上多个附件。然后,当消息的文本以内联方式引用或嵌入附件时,它开始变得困难(想象一个带有图像的HTML消息——该图像可能是一个与"本地"CSS链接的附件,也可能嵌入为例如base64数据url)。

编码是指电子邮件需要适应互联网上SMTP服务器的最低公分母。从1971年到20世纪90年代初,大多数电子邮件都是使用7位美国ASCII字符集的纯文本,而中间的SMTP邮件则依赖于这种7位框架。随着对字符集的需求变得越来越明显,同时需要发送二进制数据(如图像),8位SMTP邮件和各种将8位干净数据转换为7位的方法也出现了。其中包括可打印报价和base64。虽然7位几乎已经死了,但我们仍有历史上所有的困难需要克服。

PHP.net上有一段很好的代码可以处理多部分编码的消息,而不是重新发明轮子。请参阅hundsness dot.com上大卫的评论。你会使用这样的代码:

$mailbox = imap_open($service, $username, $password) or die('Cannot open mailbox');
// for all messages
$emails = imap_fetch_overview($mailbox, '1:1'/* . imap_check($mbox)->Nmsgs*/);
foreach ($emails as $email) {
    // get the info
    getmsg($mailbox, $email->msgno);
    // now you have info from this message in these global vars:
    // $charset,$htmlmsg,$plainmsg,$attachments
    echo $plainmsg; // for example
}
imap_close($mailbox);

(附带说明:他的代码有三个解析错误,他用"=="来表示"=="。修复这些错误,你就可以继续了。)

此外,如果你正在寻找一个"从头开始"做这件事的好博客,请查看以下内容:http://www.electrictoolbox.com/php-imap-message-parts/