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

Hello All, I am by no means a perl monk. I guess I am an intermediate Linux admin. I have searched the site and have answers to parts of the following question, but I can't seem to put it all together. Any help would be appreciated. The scenario: I need a script that will look at an arriving email. It will then strip the attachment (gif or jpeg only). It will then place the attachment into the users folder. The users folder is named the same as the first part of the email address (the part before the @ sign). It would be nice of the script could handle multiple attachements also. Again, I really appreciate any offerings on this. Thanks in advance. Monk Wanna-Be

Replies are listed 'Best First'.
Re: Remove Email Attachments
by Roger (Parson) on Jan 07, 2004 at 13:50 UTC
    There are many ways to do this. I recommend the following modules: Mail::Box to manage the mail box and Mail::Message::Attachment::Stripper to strip (multiple) attachments.

    Batch mode - I would use the powerful Mail::Box module to parse each user's mailbox, and for each of the user's mail messages, extract the (folder) name of the user from the email address line, strip all the attachments with Mail::Message::Attachment::Stripper (or similar module), and put the attachments into user's folder.

    Procmail mode - When email message comes in, load it into a scalar, extract the folder name from email address, and use Mail::Message::Attachment::Stripper to strip the attachments. You might also want to delete the attachment from the original email, just save the email message, and append some sort of notice to the modified mail message that their mail attachments are saved under their user directories.

    use strict; use IO::File; use Mail::Message::Attachment::Stripper; # load the mail message into $mail # extract user folder path into $user_folder ... my $m = Mail::Message::Attachment::Stripper->new($mail); my @attachments = $m->attachments; foreach my $a(@attachments) { next if $a->{content_type} !~ /jpe?g|gif/i; # ignore non-jpg/gif att +achemnts my $f = new IO::File "/home/$user_folder/" . $a->{filename}, "w" or die "Can not create file!"; print $f $a->{payload}; }
Re: Remove Email Attachments
by maa (Pilgrim) on Jan 07, 2004 at 13:42 UTC

    This might be a good place to start.

    You don't mention which mailserver you're running but you'll probably want to use procmail at some point although you sound like you want to deal with the attachments i>before the MTA tries to deliver the message to a maildir... procmail is normally accessed via a .forward or .qmail file in the users home directory.

    Are you planning to strip out exe files and other 'junk'? If so you should check out SpamAssasin.

    HTH - Mark
Re: Remove Email Attachments
by jonadab (Parson) on Jan 07, 2004 at 13:46 UTC

    update: Roger's answer looks even better.

    Parsing out the username is easy, if you have the SMTP envelope, or the recipient email address. (If you don't, it's not possible in the general case, since the TO header frequently does not contain the recipient's email address.)

    if ($toaddress =~ /(\S+)[@]yourdomain|yourotherdomain/) { $user = $1; } else { warn "Unknown user: $toaddress\n"; $user = 'postmaster'; # Or whoever should get slop. }

    If you don't have the envelope available, you can TRY to get the recipient's address from the To or Cc fields. Something like this might work most of the time:

    # This is untested. @users = map { /^(\S+)[@]/ ? $1 : undef } grep { /(yourdomain|yourotherdomain|yourthirddomain)$/ } map { s/\".*?\"//g; (/[<](\S+?)[>]/) ? $1 : undef } map { split /,\s*/, $_ } $headers =~ m/^(?:To|Cc)[:]\s*(.*?)$/mig; if (not @users) { warn "No users.\n"; @users = ('postmaster'); }

    For the attachments, you probably want to look at MIME-related modules on CPAN, such as MIME::Tools.

    Placing the thing in the user's home directory should be easy. Assuming *nix, you'd use something like this:

    my $filename = "attachment"; { my ($y, $m, $d) = (localtime)[5,4,3]; $y += 1900; $m += 1; $filename = join "-", $filename, $y, $m, $d; } # I assume $user and $ext are already set to the # username and the filetype extension respectively. while (-e "/home/$user/$filename.$ext") { $filename .= ('a'..'z')[rand 26]; # It is possible to be more elegant than this. } open FILEHANDLE, ">/home/$user/$filename.$ext"; binmode FILEHANDLE; # Probably not necessary on *nix. print FILEHANDLE $content; close FILEHANDLE;

    You'll need write permissions in the user's directory. If that's a problem, you can change the /home/ prefix and instead use some neutral location where all the users have directories but you have write permissions to all of them (e.g., by belonging to the group that owns them). The root user could if desired then create a link to each user's attachments directory within his home directory.


    $;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/
Re: Remove Email Attachments
by blue_cowdawg (Monsignor) on Jan 07, 2004 at 15:47 UTC

        I need a script that will look at an arriving email. It will then strip the attachment (gif or jpeg only). It will then place the attachment into the users folder.

    Ahh... yess.... This gives me flashbacks to when I worked for a major financial company just prior to Y2K. I was given the assignment to write a script similar to what you are describing. This was part of the paranoia that existed around Y2K in that management was concerned that viruses contained within binary attachments would infiltrate the network and wanted attachements "jailed" until January 5, 2000 after being virus inspected. I named the script "mailStripper" and collaborating with my bretheren in the messaging group we put the script on two machines named "chip" and "dale". I announced this in a meeting with senior VPs with an absolute straight face by my manager at the time absolutely lost it. (I didn't warn him!)

    Anyway enough of the war story! This is certainly a case of TIMTOWTDI! I echo what Brother Roger says in suggesting that you look at Mail::Message::Attachment::Stripper but also look at the whole family of MIME:: modules on CPAN. Psuedocode for how my script worked looked like:

    Open the message. Does it have attachments? Yes: Inspect each attachment is it one of the allowed types? Yes: leave attachment intact No: Strip the attachment replace it with a note to the end user that it has been stripped and jailed. No: send message on without being molested.

    Unfortunately I didn't keep a copy of the script around so I can't post it here.


    Peter L. Berghold -- Unix Professional
    Peter at Berghold dot Net
       Dog trainer, dog agility exhibitor, brewer of fine Belgian style ales. Happiness is a warm, tired, contented dog curled up at your side and a good Belgian ale in your chalice.
Re: Remove Email Attachments
by zentara (Cardinal) on Jan 07, 2004 at 17:39 UTC
    Mail::MboxParser has alot of ways to do this sort of thing. Here is a little snippet to show you the idea.
    #!/usr/bin/perl use Mail::MboxParser; my $mb = Mail::MboxParser->new('Mboxtest', decode => 'ALL'); #or #my $mbox= \*STDIN; #my $mb = Mail::MboxParser->new($mbox); # slurping for my $msg ($mb->get_messages) { print "###########################################################\n"; print $msg->header->{subject}, "\n"; print $msg->header->{from}, "\n"; print "###########################################################\n"; $msg->store_all_attachments('tmp'); my ($body) = $msg->body($msg->find_body,0); print ($body->as_string); print "###########################################################\n"; } print "############################################################\n" +; print "############################################################\n" +; print "############################################################\n" +; # we forgot to do something with the messages $mb->rewind; while (my $msg = $mb->next_message) { # iterate again # ... }