Home / Function to extract email attachments using PHP IMAP

Function to extract email attachments using PHP IMAP

This is a supplementary post in my series about having Google Analytics data sent by email and then downloading and parsing the data with PHP. This post simply contains a PHP function for extracting all the attachments of an email using the PHP IMAP functions into an array.

New function

Please note that I have created a newer, better function for extracting email message bodies and their parts so it is better not to use the function on this page any more. The new function is covered in the following posts:

Original function

I will at some point in the future refine this function to put the plain text body, html body and attachments into separate parts of the array but for the present work I simply need to get the attachments from the email and the body can be ignored.

This is slightly modified version of the code used in my earlier "Extracting attachments from an email message using PHP IMAP functions" post. Read that post for a further explanation of what this function is doing and how it works.

The $connection parameter is an already extablished connection to an IMAP or POP mailserver. The $message_number is the number of the message to extract the attachments from.

function extract_attachments($connection, $message_number) {
   
    $attachments = array();
    $structure = imap_fetchstructure($connection, $message_number);
   
    if(isset($structure->parts) && count($structure->parts)) {
   
        for($i = 0; $i < count($structure->parts); $i++) {
   
            $attachments[$i] = array(
                'is_attachment' => false,
                'filename' => '',
                'name' => '',
                'attachment' => ''
            );
           
            if($structure->parts[$i]->ifdparameters) {
                foreach($structure->parts[$i]->dparameters as $object) {
                    if(strtolower($object->attribute) == 'filename') {
                        $attachments[$i]['is_attachment'] = true;
                        $attachments[$i]['filename'] = $object->value;
                    }
                }
            }
           
            if($structure->parts[$i]->ifparameters) {
                foreach($structure->parts[$i]->parameters as $object) {
                    if(strtolower($object->attribute) == 'name') {
                        $attachments[$i]['is_attachment'] = true;
                        $attachments[$i]['name'] = $object->value;
                    }
                }
            }
           
            if($attachments[$i]['is_attachment']) {
                $attachments[$i]['attachment'] = imap_fetchbody($connection, $message_number, $i+1);
                if($structure->parts[$i]->encoding == 3) { // 3 = BASE64
                    $attachments[$i]['attachment'] = base64_decode($attachments[$i]['attachment']);
                }
                elseif($structure->parts[$i]->encoding == 4) { // 4 = QUOTED-PRINTABLE
                    $attachments[$i]['attachment'] = quoted_printable_decode($attachments[$i]['attachment']);
                }
            }
           
        }
       
    }
   
    return $attachments;
   
}

Note that not all elements in the array returned are attachments. Loop through the array and check if the ‘is_attachment’ value is true to know it’s an attachment. I would prefer to use the attachment filename as the the index for the attachment but it’s possible in email to have multiple attachments with the exact same filename.

An example print_r output for a Google Analytics email might look like this:

Array
(
    [0] => Array
        (
            [is_attachment] => 
            [filename] => 
            [name] => 
            [attachment] => 
        )

    [1] => Array
        (
            [is_attachment] => 1
            [filename] => Analytics_www.electrictoolbox.com_20090108-20090207.tsv
            [name] => Analytics_www.electrictoolbox.com_20090108-20090207.tsv
            [attachment] => ...
        )

)