Squiddy has asked for the wisdom of the Perl Monks concerning the following question:

Dear Perl Monks, I seek your wisdom (and patience)

I've included my current work below. It's a basic attempt to get mail and parse the MIME attachments. I can get the email without problems using the Mail::POP3Client. I am attempting to send the header and body of each message to the MIME Parser and save the resulting parsed text and files. When I run the script, a number of folders are created in the output directory, but with zero contents.

In other examples I've seen using MIME::Parser there seems to be an object (forgive me if it's called by another name) called $parser->parts, but I can't find it defined in the MIME::Tools (or MIME::Parser) documentation. My first probably is probably not knowing what "\*STDIN" represents. I know STDIN, but I don't want to be manually piping something to the script; I want to work with strings I already have in the script.

Your wisdom is much appriciated.

#!/usr/bin/perl -w ## import modules use lib '/Users/squiddy/sandbox/lib/'; use Mail::POP3Client; use MIME::Parser; ## create a new MIME parser object my $parser = new MIME::Parser; $parser->output_under("/Users/squiddy/sandbox/mailtemp/"); $parser->output_to_core(1); ###### code removed for simplicity ######### ## get mail $pop = new Mail::POP3Client( USER => "squiddy", PASSWORD => "notmypw", HOST => "pop3.squiddy.com", USESSL => true ); ###### code removed for simplicity ######### ## loop through each item on the POP3 server for ($i = 1; $i <= $pop->Count(); $i++) { ## get the unique email UIDL (out of a returned string "N XXXXXXX" +) $mailnum = $pop->Uidl($i); @maildat = split(" ",$mailnum); $mailnum = $maildat[1]; # print "$mailnum\n"; ## if it doesn't already exist in the database if (exists $hash{$mailnum}) { # print "nothing here\n"; } else { ###### code removed for simplicity ######### ## get email body $emailmessage = $pop->HeadAndBody($i); ###### code removed for simplicity ######### ## output the MIME parts $entity = $parser->parse($emailmessage) or die "parse failed\n +"; } } ## close the connection $pop->close(); ###### code removed for simplicity #########

Replies are listed 'Best First'.
Re: MIME::Parser tries but fails to save files
by ig (Vicar) on May 29, 2011 at 02:09 UTC

    If you want the parts to be written to disk you should not have $parser->output_to_core(1). This tells the parser to write all the decoded data to in-core data structures. By default (if you leave this out) the parts are written to disk.

    If your message is in a scalar variable (e.g. $message), rather than being read from a file handle, you can use $parser->parse_data($message).

    Something like:

    use strict; use warnings; use MIME::Parser; my $message = do { local $/; <DATA>; }; my $parser = MIME::Parser->new(); $parser->output_under("/tmp"); #$parser->output_to_core(1); $parser->parse_data($message) or die "parse failed\n"; __DATA__ MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="frontier" This is a message with multiple parts in MIME format. --frontier Content-Type: text/plain This is the body of the message. --frontier Content-Type: application/octet-stream Content-Transfer-Encoding: base64 PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aG +Ug Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg== --frontier--
Re: MIME::Parser tries but fails to save files
by ig (Vicar) on May 29, 2011 at 02:23 UTC
    not knowing what "\*STDIN" represents

    This may be more confusing than helpful. The short answer is that \*STDIN is the syntax required to pass a reference to the STDIN file handle to a subroutine (or object method).

    Symbol tables in Perl are special hashes where the keys are the names of the symbols and the values are references to special data structures called typeglobs. A typeglob contains or has links to the state of all the variables with the given name. You may already know that you can have $var, @var and %var - three different variables all with the same name. There is one symbol table entry for all three of these: the key is 'var' and the value is a typeglob.

    One of the types of values in a typeglob is a file handle. When you use something like $x = <STDIN>;, perl looks up 'STDIN' in the symbol table (a hash) and then uses the file handle of the referenced typeglob.

    Since there is no 'sigil' (the '$', '@' and '%' in front of scalar, array and hash variable names are called sigils) for a file handle, so it is difficult to refer to one directly. One way to pass a file handle to a subroutine is to pass a reference to the entire typeglob that contains the file handle. \*STDIN is such a reference. The subroutine can use the reference to the typeglob to access the file handle.

    You can read more about typeglobs in perldata and perlsub.