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

I've been building a small automated tool to go into a particular folder in Outlook, pull out attachments (which are reports I've set up to be sent to my email address in tab-delimited format), save them to a network directory for processing, and move the emails to a "processed" folder.

My first model worked okay, but I didn't particularly like the coding. It retrieved the number of the items in the folder, set an index variable, and then retrieved each item by the index. So I thought to myself, self, it would be much nicer to pick up all the items into an array, and then cycle through that.

My attempt at this did not work. This didn't really surprise me, but I'm not sure how to get it to work. Eventually I'm sure I'd want to iterate through attachments, and it would feel clunky to keep getting counts in order to set up loops.

update: Hmmm, yes, the question: Anyone know how to make this "cleaner"?

#! perl -w use strict; use Win32::OLE; my ($in, $to)=@ARGV; my $mail = new Win32::OLE('Outlook.Application'); my $ns = $mail->GetNamespace("MAPI"); my $inbox = $ns->GetDefaultFolder(6); ## the Inbox my $infolder = $inbox->Folders($in); my $tofolder = $inbox->Folders($to); my $count = $infolder->Items->Count; print "There are $count messages in the $in folder\n"; my $i=0; while($i <= $count){ #the original, which worked, but I didn't particularly care fo +r #the way the iteration was carried out #my $itm = $infolder->Items($i); ## the below line works (it returns a reference to something, +but... my $itms = $infolder->Items; for (@$itms){ ## for some reason $itms is not an array reference ## so. . . what is it? my $bdy = $_->Body; #the original line, which worked #my $bdy = $itm->Body; print "$bdy\n"; my $atm = $_->Attachments(1); #original line below #my $atm = $itm->Attachments(1); my $atmname = $atm->FileName; $_->Attachments(1)->SaveAsFile("H:\\erepts\\$i.$atmname"); $_->Move($tofolder); #below worked fine, saved to a folder on the network #$itm->Attachments(1)->SaveAsFile("H:\\erepts\\$i.$atmname"); #$itm->Move($tofolder); } $i++; } $mail->Quit();
PS: What the heck's with the 1-based collections in VBA, anyway? Must've taken me ten minutes to figure out how a zero subscript would be "out of range" ;)

Replies are listed 'Best First'.
Re: Outlook and References
by NetWallah (Canon) on Nov 19, 2005 at 06:08 UTC
    Resistance is futile ... do it the Microsoft way..
    #Change your Win32::OLE invocation to this: use Win32::OLE qw(in valof with OVERLOAD); .... foreach my $item(in $infolder->Items) { #..Do something with $item }
    Note: Untested in this context..

         "Man cannot live by bread alone...
             He'd better have some goat cheese and wine to go with it!"

      Though "resistance is futile" is certainly not exactly a happy thought, I'll give it a try -- thank you :)

      update: Thanks again -- I had an opportunity to try it, and found that not only did it work, it also doesn't look too bad.
Re: Outlook and References
by davidrw (Prior) on Nov 19, 2005 at 03:07 UTC
    Not that it necessarily (especially if it works ;) ) is a bad approach, but can you cut outlook out as the middle man? Is the email account a POP (that outlook doesn't delete from server) or IMAP account that you can poll directly (e.g. Mail::IMAPClient among others) or can you you have these report emails go to a dedicated address that your script polls (i'm assuming it could/would be a bonus to cut the reports messages out of your inbox as well)?

    Going more directly at the mail store would make it more robust and just reduce the number of parts (right now have to rely on outlook to get the mail, and Win32::OLE to control outlook to get it from there, and then finally parse it)