How to get raw email data with the imap extension?
Asked Answered
C

4

13

I'm looking for a way to download the whole raw email data (including attachment), similar to what you get by clicking "Show Original" in Gmail.

Currently, I can get the raw header and some parts of the mail body by this code:

$this->MailBox = imap_open($mailServer, $userName, $password, OP_SILENT);
...
$email->RawEmail = imap_fetchbody($this->MailBox, $msgNo, "0");
$email->RawEmail .= "\n".imap_fetchbody($this->MailBox, $msgNo, "1");

Also I know that changing the 3rd parameter of imap_fetchbody might return the encoded attachment. Guess I need a loop here to get the raw email part by part, but what's the condition to stop the loop?

Is there an easy way to get the whole email at once?

Any help would be appreciated.

Chappy answered 24/4, 2012 at 7:32 Comment(0)
E
4

My answer is "overcomplete", see Boy Baukema's answer for a more straight forward "view source" way of doing if you don't need the whole structure of the email.

If you want to fetch all, you need to fetch

As mime-message can have multiple bodies, you need to process each part after the other. To reduce load to the server use the FT_PREFETCHTEXT option for imap_fetchheader. Some example code about imap_fetchstructure in another answer that shows handling the imap connection and iterating over parts of a message already through encapsulation.

Earn answered 24/4, 2012 at 7:49 Comment(2)
scroll down, using imap_fetchbody($imap_stream, $msg_num, "") is much simpler and works like a charm!Analyzer
I'm also unsure if this answers the question as it wouldn't get the boundaries.Promenade
I
19

I came across this question when I was searching for the same issue. I knew it had to be easier than the solution by hakre and I found the right answer on the page for imap_fetchbody on a post from 5 years ago.

To get the full raw message just use the following:

$imap_stream = imap_open($server, $username, $password);
$raw_full_email = imap_fetchbody($imap_stream, $msg_num, "");

Notice the empty string as third parameter of imap_fetchbody this signifies all parts and sub-parts of the email, including headers and all bodies.

Ibadan answered 27/1, 2015 at 4:48 Comment(4)
Amazing! Does it fetch attachments?Boating
@Boating Yes, it fetches everything. The attachments do need to be decoded they normally are base64 encoded. Nowadays email providers allow to send "attachments" using OneDrive/GoogleDrive these are not true attachments, they will not be fetched.Survey
This is the best solution -- only one line for retrieve the complete message so that you can then feed it into a parser. $raw_full_email = imap_fetchbody($handle, $num, ""); $Parser = new PhpMimeMailParser\Parser(); $Parser->setText($raw_full_email);Fermentative
Has anyone else got an error from this PHP Warning: imap_fetchbody(): Bad message number in ...?Promenade
L
9

The answer by hakre is overcomplete, if you don't really care about the structure then you won't need imap_fetchstructure.

For a simple 'Show Source' you should only need imap_fetchheader and imap_body.

Example:

$conn = imap_open('{'."$mailServer:$port/pop3}INBOX", $userName, $password, OP_SILENT && OP_READONLY);
$msgs = imap_fetch_overview($conn, '1:5'); /** first 5 messages */
foreach ($msgs as $msg) {
    $source = imap_fetchheader($conn, $msg->msgno) . imap_body($conn, $msg->msgno);
    print $source;
}
Lightning answered 26/7, 2013 at 9:39 Comment(0)
E
4

My answer is "overcomplete", see Boy Baukema's answer for a more straight forward "view source" way of doing if you don't need the whole structure of the email.

If you want to fetch all, you need to fetch

As mime-message can have multiple bodies, you need to process each part after the other. To reduce load to the server use the FT_PREFETCHTEXT option for imap_fetchheader. Some example code about imap_fetchstructure in another answer that shows handling the imap connection and iterating over parts of a message already through encapsulation.

Earn answered 24/4, 2012 at 7:49 Comment(2)
scroll down, using imap_fetchbody($imap_stream, $msg_num, "") is much simpler and works like a charm!Analyzer
I'm also unsure if this answers the question as it wouldn't get the boundaries.Promenade
S
0

A common mistake is to use "\n" or PHP_EOL.

According to RFC RFC821, RFC2060, RFC1939 "\r\n" should be used. While some mailserver auto convert that mistakes, Cyrus does not and throw a nice error.

PHP_EOL is a system depending constant, it's "\n" on Linux, "\r" on Mac and "\r\n" on Windows, for example.

Furthermore imap_fetchheader() contains the trailing "\r\n" as expected. So the correct example would be:

 $source = imap_fetchheader($conn, $msg->msgno) . imap_body($conn, $msg->msgno);
Successful answered 9/4, 2014 at 21:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.