Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

PINE, Perl, pipes, and attachments

by brian_d_foy (Abbot)
on Jul 25, 2004 at 01:25 UTC ( #377209=CUFP: print w/replies, xml ) Need Help??

I read my mail in PINE, on a remote server. I've been doing it that way for years and it works for me. I never know where I might be or which computer I might be using, but I can usually telnet or ssh to this shell account.

Attachments, however, can be a pain in the butt. PINE is just a text thing. It isn't going to show me pictures or translate Word documents. Since I read this stuff on a remote account, I have to save the attachments then transfer them to my laptop. That can be a lot of steps, including choosing a file name then typing all the stuff that scp needs.

It really wasn't so much work that I felt very motivated to fix it, though. Well, until recently anyway. Lately I've received a lot of attachments that I want to save (opposed to the sorts that are trojans or virii).

Most of the mail with attachments ended up in my "to-do" mail folder, so I wrote a script to go through all of the messages in an mbox and extract all of the attachments. They end up in a sub-directory named after the email address of the sender.

#!/usr/bin/perl use strict; use warnings; use ExtUtils::Command qw(mkpath); use File::Spec::Functions qw(catfile); use Mail::MboxParser; ARGUMENT: foreach my $argument ( @ARGV ) { unless( -r $argument ) { warn "Cannot read from $argument: skipping\n"; next ARGUMENT; } my $mailbox = Mail::MboxParser->new( $argument ); unless( ref $mailbox ) { warn "Could not parse mailbox $argument!\n"; next ARGUMENT; } MESSAGE: foreach my $message ($mailbox->get_messages) { my $from = from( $message ); my $attachments = $message->get_attachments; next MESSAGE unless keys %$attachments; # no attachments my $path = catfile( $ENV{HOME}, qw(Documents Attachments), $fr +om ); { local @ARGV = ( $path ); mkpath; } ATTACHMENT: while( my( $name, $index ) = each %$attachments ) { save( $message, $path, $name, $index ); } } } sub from { my $message = shift; my $address = $message->header->{from}; if( $address =~ m/<(.*@.*)>/ ) { $address = $1 }; return $address; } sub save { my( $message, $path, $name, $index ) = @_; my $file = catfile( $path, $name ); my $last = ( sort { $b <=> $a } grep { /^\d$/ } map { s/^$file\.?//; $_ ? $_ : 0 } glob( $file . "*" ) )[0]; $file .= "." . ($last + 1) if defined $last; my $fh; unless( open $fh, "> $file" ) { warn "Could not write to $file: $!\n"; return; } unless( $message->store_entity_body( $index, handle => $fh ) ) { warn "Could not save attachment for $file: " . $message->error + . "\n"; return; } }

That works, but then I thought of an easier way. Why not just pipe the message directly to a program to do it as I read them, rather than having to stop reading mail and process the mbox file?

With PINE this is fairly easy. I have to turn on the enable-full-header-and-text option to make this work: while reading a message, type "h" to show all the gory details, then "|" to pipe the message to an external program, then "a", the name of my attachment extracter (which has to be in my PATH). The "a" program uses MIME::Parser which does all of the work, including figuring out the right filenames and saving the bits.

#!/usr/local/bin/perl5.8.0 use strict; use warnings; use ExtUtils::Command qw(mkpath); use File::Spec::Functions qw(catfile); use MIME::Parser; my $Base = $ENV{ATTACHMENT_ROOT} || $ENV{HOME}; my $message = do { local $/; <> }; my $from = from( \$message ); my $parser = MIME::Parser->new(); my $path = catfile( $Base, $from ); do { local @ARGV = ( $path ); mkpath; } unless -d $path; $parser->output_dir( $path ); my $entity = $parser->parse_data( $message ); sub from { my $message = shift; my( $from ) = $$message =~ m/^From:\s+(.*)/mg; $from =~ s/\s* \(.*?\) \s*//x; $from =~ s/.* < (.*@.*) > .*/$1/x; return $from; }

The files end up in one of my private web directories, so I go to that URL, which is just a directory listing, then choose the link to the email address of the message. There are my attachments. It's not as easy as clicking a link in web mail, but now everything that everyone sends me gets stored in an easily-accessible web directory.

The next step is a bit scary. Am I smart enough to let procmail do all of this for me? In that case I might consider ditching Perl in favor of munpack, which I saw in Wireless Hacks

--
brian d foy <bdfoy@cpan.org>

Replies are listed 'Best First'.
Re: PINE, Perl, pipes, and attachments
by b10m (Vicar) on Jul 25, 2004 at 09:33 UTC

    I know your problem. Whenever I'm not at my own machine, I log in to my server with ssh and read my mail with PINE. I mostly read my email at home though, so I just view images with qiv, but when you always have to export the attachments to your web directory, automating that task would be usefull. The problem with your approach is that it's not much faster (read: takes as much effort) as just saving the attachment straight away (hit ">", then select the attachment and hit "s"). So yes, in your case, I'd probably go for procmail. And you don't need to ditch Perl at all, you can call Perl scripts from procmail too! :)

    Oh and for viewing MS Word documents, see if you like antiword ;-)

    --
    b10m

    All code is usually tested, but rarely trusted.
Re: PINE, Perl, pipes, and attachments
by graff (Chancellor) on Jul 25, 2004 at 14:17 UTC
    I might consider ditching Perl in favor of munpack

    There will always be something handy that Perl is good for in managing mail, but munpack is definitely cool and wonderful (as is the companion tool, mpack) -- it really rocks with MH-style mail handling, where each message is stored as a separate file, 'cuz I just "munpack msgfile" to get the attachments.

      Apple's next release of osx has a new search tool called Spotlight. One of the "revolutionary new features" is that the Mail app saves every email in it's own file which is then indexed/searched on the hd.

      Not exactly new to us, but I guess it is kind of revolutionary to somebody who has been using, say, Outlook Express :-)
        it is kind of revolutionary to somebody who has been using, say, Outlook Express

        Or... **cough** Eudora **cough**

Re: PINE, Perl, pipes, and attachments
by sintadil (Pilgrim) on Jul 25, 2004 at 16:16 UTC

    The next step is a bit scary. Am I smart enough to let procmail do all of this for me?

    You could always use one of the many Perl modules that parse email attachments.

Re: PINE, Perl, pipes, and attachments
by hossman (Prior) on Jul 25, 2004 at 21:29 UTC
Security considerations
by fizbin (Chaplain) on Aug 01, 2004 at 01:23 UTC
    The next step is a bit scary. Am I smart enough to let procmail do all of this for me? In that case I might consider ditching Perl in favor of munpack, which I saw in Wireless Hacks
    Note that if you stick with this script, I'll be able to create arbitrarily named directories as your user simply by sending you mail. (The contents of the From: header are completely untrustworthy - your script doesn't prevent me from placing ../../../../home/bdfoy as my From: header) I'll also be able to create files as your username with pretty much arbitrary content (but I won't be able to overwrite existing files, thanks to the checks in MIME::Parser::Filer). Eventually, this might lead to a compromise. (If you use bash, ask yourself - do you have a ~/.bash_profile file?)

    At the very least, I'd add this line right after you get the new parser:

    $from = $parser->filer->exorcise_filename($from);
    I'd then have someone go over this script with a fine-toothed comb for security issues before invoking it automatically on arbitrary data sent over the network. (Which is what mail messages are)
    -- @/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/; map{y/X_/\n /;print}map{pop@$_}@/for@/

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: CUFP [id://377209]
Approved by ysth
Front-paged by ysth
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (9)
As of 2020-06-02 09:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you really want to know if there is extraterrestrial life?



    Results (16 votes). Check out past polls.

    Notices?