Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Sending Email to a list of people using Mail::Sender

by mlebel (Hermit)
on Aug 13, 2011 at 21:36 UTC ( [id://920188]=perlquestion: print w/replies, xml ) Need Help??

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

Hello, I would like to get some help here with sending emails to multiple recipients using Mail::Sender. My code works ok when it sits within the same script. The problem crops up when I take the list of email addresses and Move them to another file. I don't get any errors and I don't receive the emails in any of the addresses inside the list. I have tried everything and cannot get it working.

Previous code is like so: (This is the working code)

#!/usr/bin/perl use Mail::Sender $To = 'email1@example1.com,email2@example2.com'; $sender = new Mail::Sender { smtp => 'smtp.mailserver.com', from => 'script@somedomain.com, }); $Subject = 'This is a Test Email'; $sender->OpenMultipart({ to => "$To", subject => "$Subject", }); $Sender->Body; $Sender->SendLineEnc("Test line 1"); $Sender->SendLineEnc("Test line 2"); $Sender->Attach({ description => 'Test file', ctype => 'application/pdf', encoding => 'Base64', disposition => 'attachment; filename="File.pdf"; type="PDF"', file => "$File", }); $sender->Close(); exit();

Current code is like so: (This is the non working code)

Here is the line that resides inside $TestFile:

To = mail1@example1.com,email2@example2.com

And now the Code:

#!/usr/bin/perl use Mail::Sender $TestFile = "../etc/TestFile.conf"; if (!open(TESTFILE,$TestFile)) { print "ERROR: Unable to open Test File for reading: $TestFile"; exit(); } foreach $Line (<TESTFILE>) { if ($Line =~ m/To\s*=\s*(.*)/) { $To = $1; print "To = <$To>\n"; } } $sender = new Mail::Sender { smtp => 'smtp.mailserver.com', from => 'script@somedomain.com, }); $Subject = 'This is a Test Email'; $sender->OpenMultipart({ to => "\'$To\'", subject => "$Subject", }); $Sender->Body; $Sender->SendLineEnc("Test line 1"); $Sender->SendLineEnc("Test line 2"); $Sender->Attach({ description => 'Test file', ctype => 'application/pdf', encoding => 'Base64', disposition => 'attachment; filename="File.pdf"; type="PDF"', file => "$File", }); $sender->Close(); exit();

Any help is greatly appreciated!

Replies are listed 'Best First'.
Re: Sending Email to a list of people using Mail::Sender
by GrandFather (Saint) on Aug 14, 2011 at 01:04 UTC

    Your "working code" doesn't. You:

    1. are missing a ; after use Mail::Sender
    2. are missing the ( following new Mail::Sender which is better written Mail::Sender->new in any case.
    3. variously use $Sender and $sender probably to mean the same variable
    4. use $File which is not initialised anywhere

    In addition there is no need to interpolate variables into strings where only the contents of the variable is required (to      => "$To", for example). Better to simply use the variable (to      => $To,).

    One thing that would give a heads up for most of those issues is to always use strictures (use strict; use warnings; - see The strictures, according to Seuss).

    True laziness is hard work
Re: Sending Email to a list of people using Mail::Sender
by FunkyMonk (Chancellor) on Aug 14, 2011 at 10:28 UTC

      OK.. So I cleaned up a few things from the recommendations that some of you made. (thanks) I then got FunkyMonk's Message and I must say that I did read the documentation on Mail::Sender (I had to since I am new to perl and needed to know how it initially worked) I guess the real problem is that I wasn't 100% sure what they meant by "This parameter may be either a comma separated list of email addresses or a reference to a list of addresses." Initially, I had created a list of comma separated addresses(within the script) and it worked. When I moved that list to the new file, it didn't work. I assume that this is where the "reference to a list of addresses" comes in at. Perhaps Someone can give me the right syntax since I still cannot get it to work. (for the push part). Here is my "real" code that I have modified so far. Since my script is over 1000 lines therefore I am only posting a portion of it and it's very likely that I may be missing stuff. This is not my final code, this is my code in progress. ( so commented out stuff that i tried is also in there too ) Either way, the code works when within the script, it just doesn't work outside of it. Here it is:

      The options file:

      # Configuration File for Script # Set Alarm Thresholds by count of reoccurance based on 5 minutes cron + job. LowAlarmThreshold = 3 MediumAlarmThreshold = 2 HighAlarmThreshold = 1 # Set the Email Options # Email addresses are in comma separated values # To = emailaddress@yahoo.ca,someotheremailaddress@ +yahoo.ca To = emailaddress@yahoo.ca To = someotheremailaddress@yahoo.ca # To = emailaddress@yahoo.ca From = Script@domain.com SMTP_Server = smtp.isp.com # Set the Hour at which daily log rotation will happen (accepted range + is 0 - 23) LogRotateHour = 0

      The Script File:

      #!/usr/bin/perl use warnings; use Mail::Sender; &ReadConfig; &ActuallySendEmail; sub ReadConfig { $ConfigFile = "/srv/script/etc/ConfigFile.conf"; # open(CONFIGFILE, "<", $ConfigFile) or die "ERROR: Unable to open +$ConfigFile for reading"; # open $CONFIGFILE, '<', $ConfigFile or die "ERROR: Unable to open +'$ConfigFile' for reading $!"; #use feature qw(say); # while (<MCONFIGFILE>){ # next if !~ m/^To\s*=\s*(.*)/; # if $Line =~ m/^To\s*=\s*(.*)/; # say "To = <$1>\n"; # } if (!open(CONFIGFILE,$ConfigFile)) { print "ERROR: Unable to open Configuration File: $ConfigFile"; print "Fix the filepath or the file itself"; exit(); } @To = (); foreach $Line (<CONFIGFILE>) { next if ($Line =~ m/^#/); # Get Alarm Thresholds Values if ($Line =~ m/LowAlarmThreshold\s*=\s*(.*)/) { $LowAlarmThreshold = $1; print "Low Alarm Threshold = <$LowAlarmThreshold>\n"; } if ($Line =~ m/MediumAlarmThreshold\s*=\s*(.*)/) { $MediumAlarmThreshold = $1; print "Medium Alarm Threshold = <$MediumAlarmThreshold>\n" +; } if ($Line =~ m/HighAlarmThreshold\s*=\s*(.*)/) { $HighAlarmThreshold = $1; print "High Alarm Threshold = <$HighAlarmThreshold>\n"; } # Get Email Attributes Values if ($Line =~ m/To\s*=\s*(.*)/) { $To = $1; push(@To,$To); print "To = <@To>\n"; } if ($Line =~ m/From\s*=\s*(.*)/) { $From = $1; print "From = <$From>\n"; } if ($Line =~ m/SMTP_Server\s*=\s*(.*)/) { $SMTP_Server = $1; print "SMTP Server = <$SMTP_Server>\n"; } # Get LogRotate Hour Value if ($Line =~ m/LogRotateHour\s*=\s*(.*)/) { $LogRotateHour = $1; print "Log Rotate Hour = <$LogRotateHour>\n"; } } close(CONFIGFILE); } sub ActuallySendEMail { ($Flag) = @_; close(TEMPEMAILMESSAGEFILE); $TempEMailMessageFile =~ s/^>//; # $To = 'someemail@yahoo.com,exampleemailaddress@yahoo.ca'; # $To = 'exampleemailaddress@yahoo.ca'; # @Message = <TEMPEMAILMESSAGEFILE>; $Sender = new Mail::Sender({ smtp => 'smtp.isp.com', from => "\'$From\'", }); if ($Flag eq "TempEmailMessageFileOpenError") { $Subject = 'Script - Temporary email message open error'; } elsif ($Flag eq "TempEmailMessageFileLockError") { $Subject = 'Script - Temporary email message lock error'; } elsif ($Flag eq "Recovered") { $Subject = 'Script - has recovered from one or more errors'; } else { $Subject = 'Script encountered errors..'; }; print "to <@To>\n"; $Sender->OpenMultipart({ to => \@To, subject => "$Subject", }); $Sender->Body; $Sender->SendLineEnc("Script has encountered errors:"); $Sender->SendLineEnc("-----------------------------------\n"); if ($Flag eq "TempEmailMessageFileOpenError") { $Sender->SendLineEnc("ERROR: Unable to open file for writing: +$TempEMailMessageFile"); } elsif ($Flag eq "TempEmailMessageFileLockError") { $Sender->SendLineEnc("ERROR: Unable to lock file: $TempEMailMe +ssageFile"); } elsif (!open(TEMPEMAILMESSAGEFILE,$TempEMailMessageFile)) { print "\nERROR: Unable to open temporary email message file: $ +TempEMailMessageFile\n"; &PrintLog("ERROR: Unable to open temporary email message file: + $TempEMailMessageFile"); return $FAILURE; } else { @Message = <TEMPEMAILMESSAGEFILE>; print "Message = <@Message>\n"; $Sender->SendLineEnc(@Message); close(TEMPEMAILMESSAGEFILE); }; if (($Flag eq "")&&(-e $PDFile)) { $Sender->Attach({ description => 'PDF file', ctype => 'application/pdf', encoding => 'Base64', disposition => attachment; filename="File.pdf"; type="PDF"', file => "$PDFFile", }); } $Sender->Close(); return $SUCCESS; }

      So I beleive FunkyMonk is on the right track to what I am looking for. Thanks.

        I think what I would do is first write a small test script to see if the config file was being read correctly. Something like (using your config file)
        #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my $cnf_file = q{config.txt}; my %cnf = read_config($cnf_file); print Dumper \%cnf; sub read_config { my $file = shift; open my $fh, q{<}, $file or die qq{cant open *$file* to read: $!}; my %cnf; while (my $line = <$fh>){ chomp $line; next unless $line; next if $line =~ /^#/; my ($key, $value) = split /\s+=\s+/, $line; if ($key eq q{To}){ push @{$cnf{$key}}, $value; } else{ $cnf{$key} = $value; } } return %cnf; }
        output
        $VAR1 = { 'MediumAlarmThreshold' => '2', 'SMTP_Server' => 'smtp.isp.com', 'LowAlarmThreshold' => '3', 'LogRotateHour' => '0', 'To' => [ 'emailaddress@yahoo.ca', 'someotheremailaddress@yahoo.ca' ], 'HighAlarmThreshold' => '1', 'From' => 'Script@domain.com' };
        As you can see, the To key holds an array ref. Which is, apparently, what Mail::Sender requires.

        If the output is indeed as you expect I would consider a second test script which just sends a dummy email to those email addresses.

        This approach has many advantages. You take on one problem at a time (which is my top limit :-) and you end up with a collection of subs you are confident with. Also, if you hit a particular snag with one of the subs you have a simple script that you can post here and which monks can download and run. This approach, in my experience, will result in a lot more help and solutions.

        Try the script above. If it appears ok, write your test_send_email and see if that's ok.

        If there are still snags, you know where we live. :-)

Re: Sending Email to a list of people using Mail::Sender
by pvaldes (Chaplain) on Aug 13, 2011 at 23:39 UTC
    and, maybe...
    use feature qw(say); while (<TESTFILE>){ next if !~ m/^To\s*=\s*(.*)/; say "To = <$1>"; }
    instead:
    foreach $Line (<TESTFILE>) { if ($Line =~ m/To\s*=\s*(.*)/) { $To = $1; print "To = <$To>\n"; } }
Re: Sending Email to a list of people using Mail::Sender
by pvaldes (Chaplain) on Aug 13, 2011 at 23:26 UTC
    Probably a better approach will be something like this...
    open(TESTFILE,"<",$TestFile) or die "ERROR: Unable to open $TestFile f +or reading"; }
    instead:
    if (!open(TESTFILE,$TestFile)) { print "ERROR: Unable to open Test File for reading: $TestFile"; exit();
    }

      Even better would be:

      open my $testFile, '<', $TestFile or die "ERROR: Unable to open '$Test +File' for reading: $!";

      Note the use of a lexical file handle and that the die reports the OS supplied error.

      True laziness is hard work
Re: Sending Email to a list of people using Mail::Sender
by mlebel (Hermit) on Aug 14, 2011 at 00:26 UTC

    Thanks pvaldes and GrandFather, I have tried both of your methods. Both methods lead me to the same error:

    syntax error at ./scriptfile line 55, near "if !~"

    I should also have mentioned that the $TestFile also contains other options used in the script, which is initially the reason for why i used a foreach loop. here is the code if it helps any:

    foreach $Line (<TESTFILE>) { next if ($Line =~ m/^#/); if ($Line =~ m/option1\s*=\s*(.*)/) { $option1 = $1; print "option1 = <$option1>\n"; } if ($Line =~ m/option2\s*=\s*(.*)/) { $option2 = $1; print "option2 = <$option2>\n"; } if ($Line =~ m/option3\s*=\s*(.*)/) { $option3 = $1; print "option3 = <$option3>\n"; } if ($Line =~ m/option4\s*=\s*(.*)/) { $option4 = $1; print "option4 = <$option4>\n"; } # if ($Line =~ m/To\s*=\s*(.*)/) { # $To = $1; # print "To = <$To>\n"; # } if ($Line =~ m/option6\s*=\s*(.*)/) { $option6 = $1; print "option6 = <$option6>\n"; } if ($Line =~ m/option7\s*=\s*(.*)/) { $option7 = $1; print "option7 = <$option7>\n"; } if ($Line =~ m/option8\s*=\s*(.*)/) { $option8 = $1; print "option8 = <$option8>\n"; } } close(TESTFILE);

      That could be written more succinctly as:

      while (defined (my $Line = <TESTFILE>)) { next if ($Line =~ m/^#/); next if $Line !~ /(option(?:1|2|3|4|6|7))\s*=\s*(.*)/; print "$1 = <$2>\n"; } close (TESTFILE);

      although I doubt very much that the code you have shown so far is your actual code. Maybe if you showed us some real code that you have actually run and that demonstrates the problem you describe.

      True laziness is hard work
Re: Sending Email to a list of people using Mail::Sender
by pvaldes (Chaplain) on Aug 14, 2011 at 16:28 UTC

    "Initially, I had created a list of comma separated addresses(within the script) and it worked. When I moved that list to the new file, it didn't work."

    "I assume that this is where the reference to a list of addresses comes in at."

    Not, this is another concept, probably you're trying to use an external list that you simply forget (or fail) to load previously into a variable (ie: with read or open), so the list is not here.

      ***RESOLVED***

      OK, I solved my problem. Thanks to everyone who put in their feedback. Although the "style" may not be what everyone thinks it should be, it works and it works well. I will use some of your tips to cleanup the script once I have it working the way that I want.

      So.. FonkyMonk pointed me to in the right path. I still wasn't sure of the syntax so here is what I did:

      -I enabled the debug feature of Mail::Sender

      -I put all my values back in that had previously worked

      -I looked at the output of the debug and then with some print statements

      -I managed to get the same output from grabbing the information from the other file with the following relevant syntax:

      foreach $Line (<TESTFILE>) { if ($Line =~ m/To\s*=\s*(.*)/) { push(@To,$1); print "To = <@To>\n"; } } $Sender->OpenMultipart({ to => \@To, subject => "$Subject", });

      I hope this helps someone else in the future. (This ends my very first post ever in 6 years of using linux...it's a hell of a community out there.. keep up the good work everyone!)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://920188]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (4)
As of 2024-04-23 07:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found