Recipe 18.10 Extracting Attachments from Mail

18.10.1 Problem

You have one or more mail messages with MIME attachments, and you want to process these messages with a Perl program to extract files or otherwise manipulate attachments.

18.10.2 Solution

Use the MIME-Tools bundle from CPAN:

use MIME::Parser;

$parser = MIME::Parser->new( );
$parser->output_to_core(1);      # don't write attachments to disk

$message  = $parser->parse_data($MESSAGE);    # die( )s if can't parse
# OR
$message  = $parser->parse($FILEHANDLE);      # die( )s if can't parse

$head     = $message->head( );                 # object--see docs
$preamble = $message->preamble;               # ref to array of lines
$epilogue = $message->epilogue;               # ref to array of lines

$num_parts = $message->parts;
for (my $i=0; $i < $num_parts; $i++) {
  my $part         = $message->parts($i);
  my $content_type = $part->mime_type;
  my $body         = $part->as_string;

18.10.3 Discussion

Formally, a MIME message has only two parts: the head (containing headers such as From and Subject) and the body (containing the message, rather than its metadata). The body, however, has three parts: the preamble (text before the first attachment), a series of parts (the attachments), and the epilogue (text after the last attachment). This is shown in Figure 18-1.

Figure 18-1. Composition of a MIME message

In the Solution, we disable the default behavior of MIME::Parser that writes the attachments to disk. Doing so increases memory consumption because now the decoded attachments must be stored in memory, but prevents the need to clean up temporary files and directories once the attachments are no longer needed.

To write attachments to a file, replace the call to output_to_core with calls to methods that specify the directory in which to store the attachments and what to name the files. The output_under method specifies a directory under which each message will get its own subdirectory; those subdirectories will contain the decoded attachments:

# parsing creates files like /tmp/msg-1048509652-16134-0/foo.png

Alternatively, output_dir specifies a directory into which all attachment files go:

# parsing creates files like /tmp/foo.png

To clean up temporary files once parsing is done, say:


Because parsing can trigger exceptions, catch the exceptions if you want to clean up:

eval { $message = $parser->parse($FILEHANDLE) };
# ...

Whether you create files on disk, you can still treat the attachments as files by using the open method on an individual part:

for (my $i=0; $i < $num_parts; $i++) {
  my $part = $message->parts($i);
  my $fh = $part->open("r") or die "Can't open for reading: $!\n";
  while (<$fh>) {
    # reading lines from the current attachment

There are actually six different classes that form part of the MIME-Tools distribution, and each is well-documented. Start with the MIME::Tools manpage and explore from there.

18.10.4 See Also

The MIME::Tools manpage and other documentation for the MIME-Tools distribution