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

hi there ;)
I just found the script mentioned under http://www.perlmonks.org/?node_id=613374 (I want to use it for some automatic email-stuff) and I still have (after trying debugging & prints for ~100 times ^_~) the problem mentioned by the creator of this node... the mail I use for testing is nothing special... a rtf as an attachment and a test subject a "test" as a message together with the normal stuff like name,telephonenumber etc... Can somebody please tell me where the mistake is :( ?
OS is WindowsXP in this case (German version... the Path just links to my projectfolder but the script only creates HASH-files xP no .rtf or something like that :P) oh did ya notice that my "how do I name this project" sucks,too :>?

edit says: I just added the print Dumper( $MsgTxt ); which results in
$VAR1 = 'Received: by mymailserver id <01C81A05.60F5A3EC@mymailserver>; Mon, 29 Oct 2007 09:26:18 +01 +00
and there ARE unread messages in the mailbox xP if there aren't any the script tells me that I should get an unread one ;)
here are the erros I get:
MsgBS -->HASH(0x1e6bdb8)<-- Use of uninitialized value in concatenation (.) or string at C:\Dokume +nte und Einstellungen\holzner.s\Eigene Dateien\perlmail\perlguard_gu_ +version.pl line 55. at C:\Dokumente und Einstellungen\holzner.s\Eigene Dateien\perlmail\p +erlguard_gu_version.pl line 55 The size of the message is kB Continue ? Use of uninitialized value in concatenation (.) or string at C:\Dokume +nte und Einstellungen\holzner.s\Eigene Dateien\perlmail\perlguard_gu_ +version.pl line 64. at C:\Dokumente und Einstellungen\holzner.s\Eigene Dateien\perlmail\p +erlguard_gu_version.pl line 64 Full message : <emailtext & info about attachment xP> Number of email parts : 2 hash: $VAR1 = undef; + hash: $VAR1 = undef; + cou cou cou cou
here is the code I use at the moment (atm only with one "extra-print" I delete the other prints again because I think the main problem is focused at the MailBS-point):
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; use Email::Simple; use Email::MIME; use Mail::IMAPTalk; use Email::MIME::Attachment::Stripper ; use constant DUMP => 'C:\\Dokumente und Einstellungen\\holzner\.s\\Eig +ene Dateien\\perlmail\\'; my $server = 'mymailserver'; my $imap_port = '143'; my $login = 'myacc'; my $password = 'mypwd'; print "******************\n"; print "* MAIL EXTRACT *\n"; print "******************\n\n"; my $FolderName = 'THO'; print "Connecting to IMAP server at ".$server.":".$imap_port."...\n"; # open the imap connection using IMAP::Talk my $imap = Mail::IMAPTalk->new( Server => $server, Port => $imap_port, Username => $login, Password => $password, Separator => '\\', RootFolder => '',#'Inbox', I don't think I need a "ro +ot" folder at the moment because I use only one Folder for testing th +is script?? CaseInsensitive => 1) || die "Connection failed. Reason: $@"; # Select folder and get first unseen message $imap->select($FolderName) || die $@; my $MsgId = $imap->search('not', 'seen')->[0]; if ($MsgId) { # Get the enveloppe print "The message with ID ".$MsgId." has the following enveloppe: +\n"; my $MsgEV = $imap->fetch($MsgId, 'envelope')->{$MsgId}->{envelope} +; print "From: " . $MsgEV->{From}."\n"; print "To: " . $MsgEV->{To}."\n"; print "Subject: " . $MsgEV->{Subject}."\n"; print "Sender: " . $MsgEV->{Sender}."\n"; print "Continue ?\n"; getc(STDIN); # Get the message body structure my $MsgBS = $imap->fetch($MsgId, 'bodystructure')->{$MsgId}->{body +structure}; print "MsgBS -->". $MsgBS. "\<--\n"; print "The size of the message is ". $MsgBS->{Size} ."kB\n"; print "Continue ?\n"; getc(STDIN); # Find imap part number of text part of message my $MsgTxtHash = Mail::IMAPTalk::find_message($MsgBS); my $MsgPart = $MsgTxtHash->{text}->{'IMAP-Partnum'}; # Retrieve message text body my $MsgTxt = $imap->fetch($MsgId, "body[$MsgPart]")->{$MsgId}->{bo +dy}; print Dumper( $MsgTxt ); print "Full message : \n"; print "\n<-------------------------------------->\n"; print $MsgTxt."\n"; print "\n<-------------------------------------->\n"; print "Continue ?\n"; getc(STDIN); # Transform the content from IMAP:Talk into a MIME object using Em +ail:MIME my $parsed = Email::MIME->new($MsgTxt); print "Parsed content :\n". Dumper( $parsed) . "\n"; # display the MIME structure print "MIME structure :" . $parsed->debug_structure . "\n"; my $parts = $parsed->parts; print "Number of email parts : $parts\n"; my @parts = $parsed->parts; my $i=0; #foreach (@parts) { # print "Dumped email part $i:\n", # Dumper( $parts[$i] ), # "\n"; # $i++; #} my $decoded = $parsed->body; #print "body: " . Dumper( $decoded ) . "\n"; # Give the Email MIME content to Attachment::Stripper for extracti +on my $stripper; if ($parts > 1) { $stripper = Email::MIME::Attachment::Stripper->new($parts[1]); } else { die "This message consists of a single part.\n"; } die "Not an regular MIME part given to stripper:\n" if not ref $stripper; # The extraction method itself my @attachments = $stripper->attachments; # Display the resulting attachments hash $i=0; foreach (@parts) { my $j=0; foreach ($parts[$i]) { print "hash:\n" . Dumper( $attachments[$i]->{payload}) . " +\n"; $j++; } $i++; } # Close the IMAP connection $imap->logout(); # Save the attachments on the local disk foreach $i (@attachments) { my $file = 'test'.$i; #DUMP . @attachments->filename(1); print "cou"; open FILE, '>', $file or die $!; print FILE @attachments; close FILE; chmod 0644, $file; print "cou"; } } else { print "No new message in the mailbox\n" }


######
I hope someone can help me :( I'm stuck and I have tried to solve this problem by myself many (and I mean many ._.") times =( ), so please, lend me your power ;)

And I want to apologize for posting my question in the old node but I'm new at the monastery, so please forgive me my mistake.

Bye for now,
Shinama
<Sebastian>
"You read too much and understand too little." Moiraine Damodred (The Wheel of Time)

Replies are listed 'Best First'.
Re: Trying to extract an attachment
by rhesa (Vicar) on Oct 29, 2007 at 15:08 UTC
    The result of $stripper->attachments; is an array of hashrefs. Each element has 3 key-value pairs:
    { filename => "suggested filename", payload => "file contents". content_type => "mime type", }
    Provided the rest of your code correctly fetches the attachments, this loop for saving them is broken:
    # Save the attachments on the local disk foreach $i (@attachments) { my $file = 'test'.$i; #DUMP . @attachments->filename(1); print "cou"; open FILE, '>', $file or die $!; print FILE @attachments; close FILE; chmod 0644, $file; print "cou"; }
    If you're iterating over the array, you should be operating on the *current* element in the loop block, not on the array again. And you should be using each attachment's datastructure properly:
    foreach my $att ( @attachments ) { my $file = $att->{filename}; open my $fh, '>', $file or die $!; print $fh $att->{payload}; close $fh; chmod 0644, $file; }
      Hi rhesa,

      thanks for helping me :) But I still have the problem with attachment... I still get errors like
      Use of uninitialized value in concatenation (.) or string at C:\Dokume +nte und Einstellungen\holzner.s\Eigene Dateien\perlmail\perlguard_gu_ +version.pl line 55. at C:\Dokumente und Einstellungen\holzner.s\Eigene Dateien\perlmail\p +erlguard_gu_version.pl line 55 The size of the message is kB Continue ? Use of uninitialized value in concatenation (.) or string at C:\Dokume +nte und Einstellungen\holzner.s\Eigene Dateien\perlmail\perlguard_gu_ +version.pl line 65. at C:\Dokumente und Einstellungen\holzner.s\Eigene Dateien\perlmail\p +erlguard_gu_version.pl line 65 Number of email parts : 2 hash: $VAR1 = undef; hash: $VAR1 = undef;
      how is it possible that the size is "nothing"? Doesn't it mean that the script was not able to read the mail? The email I use for testing is just a normal email with a small attachment :( In addition to the "old" mistakes above your foreach results in the following error messages:
      Use of uninitialized value in open at C:\Dokumente und Einstellungen\h +olzner.s\Eigene Dateien\perlmail\perlguard_gu_version.pl line 132. at C:\Dokumente und Einstellungen\holzner.s\Eigene Dateien\perlmail\p +erlguard_gu_version.pl line 132 No such file or directory at C:\Dokumente und Einstellungen\holzner.s\ +Eigene Dateien\perlmail\perlguard_gu_version.pl line 132. at C:\Dokumente und Einstellungen\holzner.s\Eigene Dateien\perlmail\p +erlguard_gu_version.pl line 132 </code it seems like the script doesn't recognize the key pair ? but how is t +hat (empty attachment array) possible?


      I'm sorry to bother you with such stupid beginner problems but I don't understand it :(

      Do you have any idea how I could fix that whole problem :(? Here is the current version of the script (I have blocked most of the prints to get rid of the print spamming :( )

      Could it be that the problem already starts at the MsgBS-part? This is the beginning of the errors?

      #!/usr/bin/perl use strict; use warnings; use Data::Dumper; use Email::Simple; use Email::MIME; use Mail::IMAPTalk; use Email::MIME::Attachment::Stripper ; use constant DUMP => 'C:\\Dokumente und Einstellungen\\holzner\.s\\Eig +ene Dateien\\perlmail\\'; my $server = 'mymailserver'; my $imap_port = '143'; my $login = 'mylogin'; my $password = 'mypwd'; print "******************\n"; print "* MAIL EXTRACT *\n"; print "******************\n\n"; my $FolderName = 'THO'; print "Connecting to IMAP server at ".$server.":".$imap_port."...\n"; # open the imap connection using IMAP::Talk my $imap = Mail::IMAPTalk->new( Server => $server, Port => $imap_port, Username => $login, Password => $password, Separator => '\\', RootFolder => '',#'Inbox', CaseInsensitive => 1) || die "Connection failed. Reason: $@"; # Select folder and get first unseen message $imap->select($FolderName) || die $@; my $MsgId = $imap->search('not', 'seen')->[0]; if ($MsgId) { # Get the enveloppe print "The message with ID ".$MsgId." has the following enveloppe: +\n"; my $MsgEV = $imap->fetch($MsgId, 'envelope')->{$MsgId}->{envelope} +; print "From: " . $MsgEV->{From}."\n"; print "To: " . $MsgEV->{To}."\n"; print "Subject: " . $MsgEV->{Subject}."\n"; print "Sender: " . $MsgEV->{Sender}."\n"; print "Continue ?\n"; getc(STDIN); # Get the message body structure my $MsgBS = $imap->fetch($MsgId, 'bodystructure')->{$MsgId}->{body +structure}; print "MsgBS -->". $MsgBS. "\<--\n"; print "The size of the message is ". $MsgBS->{Size} ."kB\n"; print "Continue ?\n"; getc(STDIN); # Find imap part number of text part of message my $MsgTxtHash = Mail::IMAPTalk::find_message($MsgBS); my $MsgPart = $MsgTxtHash->{text}->{'IMAP-Partnum'}; # Retrieve message text body my $MsgTxt = $imap->fetch($MsgId, "body[$MsgPart]")->{$MsgId}->{bo +dy}; #print Dumper( $MsgTxt ); #print "Full message : \n"; #print "\n<-------------------------------------->\n"; #print $MsgTxt."\n"; #print "\n<-------------------------------------->\n"; #print "Continue ?\n"; getc(STDIN); # Transform the content from IMAP:Talk into a MIME object using Em +ail:MIME my $parsed = Email::MIME->new($MsgTxt); #print "Parsed content :\n". Dumper( $parsed) . "\n"; # display the MIME structure #print "MIME structure :" . $parsed->debug_structure . "\n"; my $parts = $parsed->parts; print "Number of email parts : $parts\n"; my @parts = $parsed->parts; my $i=0; #foreach (@parts) { # print "Dumped email part $i:\n", # Dumper( $parts[$i] ), # "\n"; # $i++; #} my $decoded = $parsed->body; #print "body: " . Dumper( $decoded ) . "\n"; # Give the Email MIME content to Attachment::Stripper for extracti +on my $stripper; if ($parts > 1) { $stripper = Email::MIME::Attachment::Stripper->new($parts[1]) } else { die "This message consists of a single part.\n"; } die "Not an regular MIME part given to stripper:\n" if not ref $stripper; # The extraction method itself my @attachments = $stripper->attachments; # Display the resulting attachments hash $i=0; foreach (@parts) { my $j=0; foreach ($parts[$i]) { print "hash:\n" . Dumper( $attachments[$i]->{payload}) . " +\n"; $j++; } $i++; } # Close the IMAP connection $imap->logout(); # Save the attachments on the local disk foreach my $att ( @attachments ) { my $file = $att->{filename}; open my $fh, '>', $file or die $!; print $fh $att->{payload}; close $fh; chmod 0644, $file; } } else { print "No new message in the mailbox\n" }


      Thanks a lot for helping me :) I just read in an german forum that a much better perl programmer than me needed 6 months for doing something similiar to this :( So this means that I need 1-2 years ._."?

      bye for now,
      Shinama
      "You read too much and understand too little." Moiraine Damodred (The Wheel of Time)
Re: Trying to extract an attachment
by Anonymous Monk on Oct 29, 2007 at 13:26 UTC
    there is no mistake?
      But shouldn't the script return / "re-"create the attachments at the path I used??

      All it(the script) creates are HASH-files (testHASH(0x1bfc904) <-- for example) which only contain the same HASH (testHASH(0x1bfc904) in this case)

      All I want to do is a script which extracts the attachment and copies it to a given path? And as far as I understand Perl (to be honest that doesn't mean much =( ) that script "should" do that? I mean if the current result is correct... what does this script then? HASHes alone aren't very useful^^"? (Or is there something that is missing in this script? Like de"crypt" the Hash again?)

      Thanks for your help, Shinama

      "You read too much and understand too little." Moiraine Damodred (The Wheel of Time)