charlie
charlie

Reputation: 1384

imap_open function in PHP sometimes see blank message body

I am using imap_open function in PHP to download emails and insert them into a mysql database

Here is my code to get the headers and body message etc:

$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));
    }
}
}

but it doesnt seem to get the body of all emails. For example, when it receives Read Receipts the body is just blank and the same with some other emails people send.

sometimes, the email body looks like:

PGh0bWw+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIgY29udGVudD0i dGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4NCjwvaGVhZD4NCjxib2R5IHN0eWxlPSJ3b3JkLXdy YXA6IGJyZWFrLXdvcmQ7IC13ZWJraXQtbmJzcC1tb2RlOiBzcGFjZTsgLXdlYmtpdC1saW5lLWJy ZWFrOiBhZnRlci13aGl0ZS1zcGFjZTsgY29sb3I6IHJnYigwLCAwLCAwKTsgZm9udC1zaXplOiAx NHB4OyBmb250LWZhbWlseTogQ2FsaWJyaSwgc2Fucy1zZXJpZjsiPg0KPGRpdj4NCjxkaXY+DQo8 ZGl2PnJlcGx5PC9kaXY+DQo8ZGl2Pg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBDYWxpYnJpOyBt YXJnaW46IDBweCAwcHggMTJweDsiPjxiPktpbmQgUmVnYXJkcyw8YnI+DQo8YnI+DQpDaGFybGll IEZvcmQgfCZuYnNwOzwvYj48c3BhbiBzdHlsZT0iY29sb3I6IHJnYigyNTIsIDc5LCA4KTsiPjxi PlRlY2huaWNhbCBNYW5hZ2VyJm5ic3A7PC9iPjwvc3Bhbj48Yj58Jm5ic3A7SW50ZWdyYSBEaWdp dGFsPC9iPjxmb250IGNvbG9yPSIjNTk1OTU ... continued

How can i convert the whole message body to be plain text

Upvotes: 2

Views: 2012

Answers (2)

bishop
bishop

Reputation: 39404

The code given handles only simple text messages having at most one sub-part and no encoding. This is basically the simplest kind of email there is. The world used to be that simple, sadly no more!

To handle more email, your code must be expanded to handle:

  1. Multi-parts
  2. Encodings

Multi-part is the concept that a single email message (a bunch of data) can be divided into multiple, logically-separate pieces. In the simplest case, there is only one part: the text of the message. In the next simplest case, there is message text with a single attachment. The next simplest case is message text plus multiple attachments. Then it starts to get hard, when the text of the message refers inline or embeds the attachments (think of an HTML message with an image -- that image could be an attachment that's linked with "local" CSS or embedded as eg base64 data url).

Encoding is the idea that email needs to accommodate the lowest common denominator of SMTP servers on the Internet. From 1971 to the early 1990s, most email messages were plain text using 7-bit US ASCII character set -- and SMTP mailers in the middle relied on this 7-bit framework. As the need for character sets became more apparent, simultaneously with the need to send binary data (eg images), 8-bit SMTP mailers cropped up as did various methods to shoe-horn 8-bit clean data into 7-bits. These include quoted-printable and base64. While 7-bit is virtually dead, we still have all the hoops of this history to jump through.

Rather than re-invent the wheel, there is a good piece of code on PHP.net that handles multi-part encoded messages. See the comment by david at hundsness dot com. You would use that code like this:

$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);

(Side note: his code has three parse errors, where he does ". =" to mean ".=". Fix those and you're good to go.)

Also, if you're looking for a good blog on doing this "from the ground up", check out this: http://www.electrictoolbox.com/php-imap-message-parts/

Upvotes: 1

bishop
bishop

Reputation: 39404

Here's what I use, in general. $email refers to one of the objects from the return of eg 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);
}

Note there are 6 possible encodings (ranging from 0 to 5), and I'm only handling 2 of them (3 and 4) -- you might want to handle all of them.

Also note I'm also getting only the 1st part (in imap_fetchbody) -- you might want to loop over the pieces to get them as needed.

Update
One other thing I noticed about your code. You're doing imap_fetchbody($inbox,$email_number,1.1). That third argument should be a string, not a number. Do this instead:

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

Upvotes: 1

Related Questions