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

Here's the situation: I have 8 csv files that need to be archived and emailed to 8 different addresses once a day (I'll cron that, that much I know).

I have sent one file to one address before using the following code:

#!/usr/bin/perl -w # casma_archive.pl # script to email and archive CASMA registration files use MIME::Lite; $data_path = "/actapps/suitespot/cgi-bin/forms"; $archive_dir = "/actapps/suitespot/cgi-bin/forms/archive"; $from_email = "me\@someplace.org"; $to_email = "her\@someotherplace.org"; $file_date = &sys_date; #get the current date to append to file name $orig_file = "casma.csv"; $new_file = "casma_$file_date.csv"; $subject = "CASMA registrations flatfile"; archive_results($to_email, $orig_file, $new_file, $subject); sub archive_results { my($to_email, $old_file, $new_file, $subject) = @_; #name subroutine v +ariables system("mv $data_path/$old_file $data_path/$new_file"); #rename the fl +atfile with date $msg = MIME::Lite->new(From => $from_email, To => $to_email, Subject => $subject, Type => 'multipart/mixed'); + $msg->attach(Type => 'application/octet-stream', Path => "$data_path/$new_file", Filename => $new_file ); $msg->send(); system("mv $data_path/$new_file $archive_dir/$new_file"); #move flatfi +le to archive directory } sub sys_date{ my %mn = ('Jan','01', 'Feb','02', 'Mar','03', 'Apr','04', 'May','05', 'Jun','06', 'Jul','07', 'Aug','08', 'Sep','09', 'Oct','10', 'Nov','11', 'Dec','12' ); my $sydate=localtime(time); my ($day, $month, $num, $time, $year) = split(/\s+/,$sydate); my $zl=length($num); if ($zl == 1) { $num = "0$num";} my $retval="$mn{$month}$num$year"; return $retval; }

I've looked at it a dozen different ways and I cannot figure out how to use this same code/subroutine to do it multiple times. I'm sure I need to make a hash of something and foreach, but I'm still working on understanding hashes (great replies, I'm still processing them all).

I'm unsure if I'm renaming the file in a good way or not.

Please ask as many questions for clarification as needed.

TIA
~ WD

~~~UPDATE~~~~

Thanks to the suggestions, I was able to answer my questions and make my code a bit neater and really help my understanding of hashes, though its an never ending battle. I ended up keying off the file names instead of the email because two files were to go to the same email address. I'm sure there is a fancy way to do that with the email addresses still as the keys, but I know the file names will remain unique even if email addresses change.

In the end I have
$file_date = POSIX::strftime("%C%y%m%d", localtime); #get the current +date to append to file name while (my ($filename, $recipient ) = each %csv_files) { my $newname = $file_date.$filename; archive_results($recipient, $filename, $newname, $subject); } exit 0; sub archive_results { my($to_email, $old_file, $new_file, $subject) = @_; #name subroutine v +ariables if (-e $old_file) { #only if file exists system("mv $data_path/$old_file $data_path/$new_file"); #renam +e the flatfile with date $msg = MIME::Lite->new(From => $from_email, To => $to_email, Subject => $subject, Type => 'multipart/mixed'); + $msg->attach(Type => 'application/octet-stream', Path => "$data_path/$new_file", Filename => $new_file ); $msg->send(); system("mv $data_path/$new_file $archive_path/$new_file"); #mo +ve flatfile to archive directory } } #end archive_results

Which works great. My clients are pleased. Now if I could only figure out why my cron won't run, it would be perfect. But that's for the unix admin to figure out since all my other ones work fine and this script executes flawlessly from the command line.

Replies are listed 'Best First'.
Re: Appending to filenames, system mv, using MIME::Lite and other fun
by Nkuvu (Priest) on Jul 26, 2005 at 21:13 UTC
    I have 8 csv files that need to be archived and emailed to 8 different addresses once a day
    Explain this a bit more? You have 8 CSV files -- do they all go to each of the 8 addresses, or is there a correspondence between each CSV file and a particular address?

    For example, let's say the CSV files are named a.csv, b.csv, et cetera. Your first recipient is john_q_public@foobar.com. Does he get all 8 csv files? Only a.csv? Some subset (i.e., John needs a.csv, d.csv, and f.csv, but no others)? The answer to that will change how to approach the hash.

    Unrelated to the hashes, you can simplify part of your code. Specifically, the sys_date sub can be replaced by POSIX::strftime. At the top of your script add use POSIX then the sys_date sub call can be replaced with something like:
    $file_date = POSIX::strftime("%b%d%Y", localtime);

    See strftime docs for all of the available formats.

      Obviously that makes a huge difference. There is a correspondence between each file. One file goes to one address. Thanks for the POSIX suggestion. I'll give that a try.
        In that case you can create a simple lookup. Something akin to (using my previously named examples):

        my %csv_recipients = ( 'john_q_public@foobar.com' => 'a.csv', 'jane_q_public@xyz.com' => 'b.csv', 'some_other_address@example.com' => 'c.csv' # and so on );

        Then to send it out just change your call to archive_results:

        while (my ($recipient, $filename) = each %csv_recipients) { archive_results($recipient, $orig_file, $filename, $subject); }
        or similar. Code untested, void where prohibited by law, et cetera et cetera ad nauseum.
Re: Appending to filenames, system mv, using MIME::Lite and other fun
by GrandFather (Saint) on Jul 26, 2005 at 21:22 UTC

    Repeat the $msg->attach for each file.

    Add a Cc => '2@other.com, ..., 7@other.com' entry to the MIME::Lite->new or change $to_email to be the list of recipients


    Perl is Huffman encoded by design.
Re: Appending to filenames, system mv, using MIME::Lite and other fun
by cajun (Chaplain) on Jul 26, 2005 at 21:27 UTC
    I've read this a couple of times and it's not clear to me either if all of the .csv files are going to all of the recipients or not. If all 8 files are going to all 8 recipients, then I would create @recipients and @files. Then just use a couple of foreach loops.

    If the files are being mailed one per recipient, this will not work. That may well be the case since you're working on understanding hashes.

    Thanks,
    Mike