Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Email To A List Of Addresses

by Milti (Sexton)
on Feb 02, 2017 at 20:01 UTC ( [id://1180881]=perlquestion: print w/replies, xml ) Need Help??

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

I send periodic emails to a variety of clients and the addresses change with the variety. I currently a form for the email composition and address the email to "undisclosed recipients (my email address) with BCC's going to the individual clients. I use the following code to accomplish that.

##sendmail_email.pl #!C:/Perl/bin/perl -w use CGI qw(:standard); use HTML::Entities; use Mail::Sendmail 0.79; # doesn't work with v. 0.74! my $Recipient=param('Recipient'); my $Sender=param('Sender'); my $bcc_list=param('bcc_list'); my $Subject=param('Subject') my $Message = param ('Message'); $html = <<END_HTML; <p>$Message</p><p><font size="2"> END_HTML my %mail; $mail{Smtp}="smtp.sendgrid.net"; $mail{Port}=587; $mail{Auth}={user=>"Milt1", password=>"XXXXXXX", method => "LOGIN", re +quired => 1}; $mail{To}=$Recipient; $mail{From}= $Sender; $mail {bcc}="$bcc_list"; $mail{Subject}=$Subject; $mail{'content-type'} = 'text/html; charset="iso-8859-1"'; $mail{body} = <<END_OF_BODY; <html>$html</html> END_OF_BODY sendmail(%mail) || print "Error: $Mail::Sendmail::error\n"; &redirect; sub redirect { print header(), start_html; print "Your Message Was Sent\n\n"; } exit;

I want to address each client individually by name and not utilize BCC's. Can this be done without reading from a 'file' saved on the server or can it be done by pasting the list into text area on the form named "Email_List", input into the cgi as: my $Email=param ('Email_List'); put into and array and read with a foreach loop? Something like this:

my@=<$Email>; if (@a) { foreach $Address(@a) { $Recipient=$Address; } }

I haven't been able to get any of several trials to work. Any help/suggestions will be sincerely appreciated. Thanks!

Replies are listed 'Best First'.
Re: Email To A List Of Addresses
by kennethk (Abbot) on Feb 02, 2017 at 21:38 UTC
    I'm assuming that, since you are using a form, the data is coming in from an application/x-www-form-urlencoded POST. You have the option of passing the data either as a single field value that you'll pull in as a scalar:
    my $email_list = param ('Email_List');
    or you can have a large number of inputs (one for each address) and use array access to the parameters:
    my @email_list = param ('Email');
    Note that this capability to have repeat keys in HTTP requests has caused a large number of issues over the years, because people can completely miss entries if they call param in scalar context. This means it might be a future gotcha. You'll also probably want some javascript on you page for 'Add additional recipient' in that scenario.

    Your post sounds like you would prefer a big cut-paste blob into a textbox, and then process that list on the server. A split as Corion suggests would then be a natural processing approach, but could easily be frustrated depending on how you are formatting you list. If you want to include addresses of the format

    Smith, Peter (PERL) <peter.smith@perl.com>
    you couldn't use commas as separators, for example. Regardless, you could implement your loop with something like:
    ##sendmail_email.pl #!C:/Perl/bin/perl -w use CGI qw(:standard); use HTML::Entities; use Mail::Sendmail 0.79; # doesn't work with v. 0.74! my $Sender=param('Sender'); my $email_list=param('Email_List'); my $Subject=param('Subject') my $Message = encode_entities(param ('Message')); #SEE WHAT I DID HERE $html = <<END_HTML; <p>$Message</p><p><font size="2"> END_HTML for my $email (split /;/, $email_list) { my %mail; $mail{Smtp}="smtp.sendgrid.net"; $mail{Port}=587; $mail{Auth}={user=>"Milt1", password=>"XXXXXXX", method => "LOGIN" +, required => 1}; $mail{To}=$email; $mail{From}= $Sender; $mail{Subject}=$Subject; $mail{'content-type'} = 'text/html; charset="iso-8859-1"'; $mail{body} = <<END_OF_BODY; <html>$html</html> END_OF_BODY sendmail(%mail) || print "Error: $Mail::Sendmail::error\n"; } &redirect; sub redirect { print header(), start_html; print "Your Message Was Sent\n\n"; } exit;

    Finally, as a side note, depending on how visible this service is, you have some mighty security holes present there. At the least, someone can use this as a SPAM generator, and will be able to do so even more once they could submit 1000 email addresses in a go. There are also like some injection attack sensitivities, since you have not done any input filtering and are just interpolating.


    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

      Thanks for the responses. The form that I'm using is on my office computer and not readily available (I hope) to anyone else. The cgi program is located on a remote server.You are correct in that I would like to simply paste a list into a text box on the form as something like this:

      John Smith (john.smith@earthlink.net)
      Bill Jones (bill_jones@hiscompany.com)
      etc
      etc

      Then I would like to put the "lines/addresses" in an array and utilize a foreach loop to send individual emails.

      Does this sound reasonable or do I have to worry about a delimiter?

      Once again, thanks for any advice you can offer.

        You have a delimiter there: newlines. Assuming they don't get passed through a layer that mangles white space at any point, it should work. Make sure to get your input box wide enough that you don't get bit by wrapping on
        John Smith (john.smith@earthlink.net) Bill Jones (bill_jones@hiscompany.com) Bill Jones (bill_jones@hisc +ompany.com) etc etc

        Note that the security problem is not with the machine that views the form, but with the remote server. Anyone on the Internet could craft an HTTP request to fool your remote server into sending messages unless you, say, configure Apache to whitelist only service requests from your machine. Right now you can operate because no one has found your service, but security-through-obscurity is not a good model. Other than helping a spammer, the other major risk is that a spammer gets your server blacklisted. And that's presuming they don't take advantage of some obscure sendmail bug to own your remote server.


        #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

        If all the email addresses are enclosed in brackets then perhaps use a simple regex to extract them. Here is a basic test script to play around with. The added confirm checkbox lets you test before actually sending.

        #!C:/Perl/bin/perl -w use strict; use CGI ':standard'; my $MAX = 10; # maximum in list my %list = (); my $confirm = param('confirm'); my $Email_List = param('Email_List'); # extract email adressess between () while ( $Email_List =~ m/\(([^)]+)/g ){ my $addr = $1; # remove spaces and any other cleaning here # assuming you don't have unusual addresses like # "Any Person"@somewhere.com $addr =~ s/ //g; # check valadity if ( is_valid($addr) ){ $list{$addr} = 'Not sent'; # using key avoids duplicates } } # check not too many my $msg; my $no = scalar(keys %list); if ($no > $MAX){ $msg = "ERROR - $no is too many to send"; } else { # send emails if confirm checked if ($confirm){ for (keys %list){ $list{$_} = send_to($_); # store result } } } # input form print header(), start_html; print qq!<h4>Recipients (maximum $MAX)</h4> <form action="" method="post"> <textarea cols="80" rows="20" name="Email_List"> $Email_List </textarea><br/> <br/> Confirm<input name="confirm" type="checkbox"/> <input type="submit" name="action" value="Send"/> </form><br/> <span style="background-color:#ffff00">$msg</span>!;
        poj
Re: Email To A List Of Addresses
by Corion (Patriarch) on Feb 02, 2017 at 20:32 UTC

    Depending on how you send the Email_List parameter to your script, maybe split helps you to split that parameter up into the parts? split returns an array over which you then could iterate to send the mail.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2024-04-25 13:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found