Get message body and attachments using PHP IMAP
Posted January 11th, 2012 in PHP
The last post looked at how to get a message structure using the PHP IMAP functions into an easier to use flat array. This post looks at how to loop through that array to easily get all the message parts and attachments.
PHP code to flatten the IMAP structure
The function in the previous post is called flattenParts. Refer to that post for more details, but to save time if you don't wish to read that post as well here's another copy of the same function:
function flattenParts($messageParts, $flattenedParts = array(), $prefix = '', $index = 1, $fullPrefix = true) {
foreach($messageParts as $part) {
$flattenedParts[$prefix.$index] = $part;
if(isset($part->parts)) {
if($part->type == 2) {
$flattenedParts = flattenParts($part->parts, $flattenedParts, $prefix.$index.'.', 0, false);
}
elseif($fullPrefix) {
$flattenedParts = flattenParts($part->parts, $flattenedParts, $prefix.$index.'.');
}
else {
$flattenedParts = flattenParts($part->parts, $flattenedParts, $prefix);
}
unset($flattenedParts[$prefix.$index]->parts);
}
$index++;
}
return $flattenedParts;
}
Functions for getting the content and filename for a part
The looping function below relies on another couple of functions which get the message or attachment content and the filename when it's an attachment. These are as follows:
function getPart($connection, $messageNumber, $partNumber, $encoding) {
$data = imap_fetchbody($connection, $messageNumber, $partNumber);
switch($encoding) {
case 0: return $data; // 7BIT
case 1: return $data; // 8BIT
case 2: return $data; // BINARY
case 3: return base64_decode($data); // BASE64
case 4: return quoted_printable_decode($data); // QUOTED_PRINTABLE
case 5: return $data; // OTHER
}
}
function getFilenameFromPart($part) {
$filename = '';
if($part->ifdparameters) {
foreach($part->dparameters as $object) {
if(strtolower($object->attribute) == 'filename') {
$filename = $object->value;
}
}
}
if(!$filename && $part->ifparameters) {
foreach($part->parameters as $object) {
if(strtolower($object->attribute) == 'name') {
$filename = $object->value;
}
}
}
return $filename;
}
Looping through the message parts
And finally, here's the code to connect to the IMAP server, download the first message and then loop through it to get the various message parts. Modify this code to suit your own circumstances. You can get the second, third, etc message by changing the $messageNumber variable.
$connection = imap_open($server, $login, $password);
$messageNumber = 1;
$structure = imap_fetchstructure($connection, $messageNumber);
$flattenedParts = flattenParts($structure->parts);
foreach($flattenedParts as $partNumber => $part) {
switch($part->type) {
case 0:
// the HTML or plain text part of the email
$message = getPart($connection, $messageNumber, $partNumber, $part->encoding);
// now do something with the message, e.g. render it
break;
case 1:
// multi-part headers, can ignore
break;
case 2:
// attached message headers, can ignore
break;
case 3: // application
case 4: // audio
case 5: // image
case 6: // video
case 7: // other
$filename = getFilenameFromPart($part);
if($filename) {
// it's an attachment
$attachment = getPart($connection, $messageNumber, $partNumber, $part->encoding);
// now do something with the attachment, e.g. save it somewhere
}
else {
// don't know what it is
}
break;
}
}
Dealing with inline attachments
Images can be attached inline in the HTML and there's a special way they are embedded. As with regular attachments, these are just another "part" in the email. I'll look at how to deal with these tomorrow.
Related posts:
- Fetch message parts into a flat array with PHP IMAP (Tuesday, January 10th 2012)
- Articles about how to use PHP's IMAP Functions (Monday, June 1st 2009)

Comments