Here are some code snippets you might find helpful, from stuff from work I wrote that I probably can't share in full:
my $p= MIME::Parser->new;
$p->output_to_core(1);
$p->parse($msg_or_fh);
# Find every MIME part which is not a container for other parts
sub _leaf_parts {
my @parts= $_->parts;
@parts? ( map { _leaf_parts() } @parts ) : ( $_ )
}
my @leaf_parts= map { _leaf_parts() } $email;
# Open a handle to each part which is an attachment
my @attachments=
map +{
name => $_->head->recommended_filename,
content_type => _decoded_mime_header($_->head, 'Content-Type'
+),
handle => $_->bodyhandle->open('r'),
mimepart => $_,
email => $email
},
grep length($_->head->recommended_filename//''), @leaf_parts;
# Convert zipfile attachments to the list of files within
@attachments= map { $_->{name} =~ /\.zip$/? _extract_zipfile($_) :
+($_) } @attachments;
# Takes one file info, and returns a list of file infos for each file
+within the zip file.
# Since these are not directly MIME parts, they are simply:
# {
# name => $original_filename,
# handle => $io_handle
# }
sub _extract_zipfile {
my ($file)= @_;
my @files;
my $zipfile= IO::Uncompress::Unzip->new($file->{handle})
or die "Can't open zip file: $UnzipError";
my $status;
for ($status= 1; $status > 0; $status= $zipfile->nextStream()) {
my $name= $zipfile->getHeaderInfo->{Name};
$log->info("Extracting $name from zip file");
my $tmp= File::Temp->new(TEMPLATE => 'email-zip-content-XXXXXXX'
+);
my $buf;
while (($status= $zipfile->read($buf)) > 0) {
$tmp->print($buf) or die;
}
last if $status < 0;
push @files, { name => $name, handle => $tmp };
}
die "Error processing zip file"
if $status < 0;
return @files;
}