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

I'm building a form mailer consisting of two textfields and one textarea that will send out those ultra-fancy HTML-formatted emails.

The big idea is for my client to paste his code into the textarea and the script will read a flat file of email addresses, tuck them into an array and interate through the list. It's one .cgi file using CGI.pm and its syntax for the creation of the form. It works perfectly if I hard-code an address in the $to variable, but when I have read in a test file (consisting of 3 addresses), it only sends the message to the first recipient, but if I print the contents of the array, my 3 values are intact.

What's more, when I attempt to test the script using the array values, my email client shows the raw HTML, but if I use the single-address test, I get the page that looks all nifty.

The magic is housed in a subroutine, and I've been focusing on my code for populating the array and my foreach loop--I know this is staring me in the face, but I'm fairly new to Perl and I've had no success in crafting a solution together perusing the site and my now well-worn copy of the Llama book. (Although it's done wonders for my syntax!) Please help? My subroutine is as follows:

sub send_message { $dir = "/blast/"; $file = "${dir}/file.txt"; open MAILIST, "<$file" or die "Can't create filehandle: $!"; while(<MAILIST>) { push (@address, $_); } close MAILIST or die "Can't close filehandle:$!"; $mailprogram = '/usr/lib/sendmail'; open( MAIL,"|$mailprogram -t" ) or die "Can't open sendmail! ($!)"; foreach (@address) { $from = $q->param( 'mail_from' || '' ); $subject = $q->param( 'mail_subject' || '' ); $message = $q->param( 'html_message' || '' ); $headers = "Content-Type: text/html; charset=iso-8859-1\r\n"; $headers .= "MIME-Version: 1.0\r\n"; $headers .= "Content-Transfer-Encoding: 7bit\r\n"; print MAIL "To: $_\n"; print MAIL "From: $from\n"; print MAIL "Subject: $subject\n"; print MAIL '$headers'; print MAIL '$message'; } return close(MAIL); }

Thankyouthankyouthankyou!

"Do or do not--there is no try." --Yoda

Replies are listed 'Best First'.
Re: Sending HTML-formatted mail to a list
by thpfft (Chaplain) on Dec 16, 2001 at 10:23 UTC

    Most of your problems will go away if you chomp each line as you read it from the address file. The closing \n on each address, which chomp will remove, is currently combining with the \n in your To: line to end the message header. I think. So:

    while(<MAILIST>) { chomp; push (@address, $_); }

    But on the other hand, all of your (mailing) problems will go away if you use something like Mail::Sendmail instead. It will cheerfully handle multiple addresses and whatever content-type you like. Or better still, set up a mailing list and just send a single message to that...

    Your other problem is in the message itself:

    print MAIL '$headers';

    The single quotes mean that the variable is not interpolated, so you are literally printing the dollar sign followed by 'headers'. If you want the contents of the variable, the string must be enclosed in double-quotes or an equivalent.

    But you don't need quotes anyway, in this case: print MAIL $headers; will do just fine.

    ps. mutter use strict mutter taint-checking mutter mutter hardcoded sendmail path mutter.

     

    update: one more thing. this isn't right:

    $message = $q->param( 'html_message' || '' );

    It works, but it isn't performing the test you want. translated, it would read something like 'the input parameter whose name is 'html_message', or if 'html_message' is false, the one whose name is empty'. But 'html_message' is always true, as is any other unempty string except '0', so you are (fortunately) never moving on to the second alternative. I think you meant:

    $message = $q->param( 'html_message' ) || '';

    But you don't really need the || '' anyway: $message will be empty with or without it.

Re: Sending HTML-formatted mail to a list
by Beatnik (Parson) on Dec 16, 2001 at 16:56 UTC
    Altho I'm not comfortable with MIME, it's similar to HTTP so this could be an issue :

    You don't have a double newline to close the HTTP|MIME header.
    Secondly, you once use \r\n, next you only use \n... Be consistent.

    Greetz
    Beatnik
    ... Quidquid perl dictum sit, altum viditur.
Re: Sending HTML-formatted mail to a list
by Chady (Priest) on Dec 16, 2001 at 20:39 UTC

    This looks rather strange:

    open( MAIL,"|$mailprogram -t" ) or die "Can't open sendmail! ($!)"; foreach (@address) { $from = $q->param( 'mail_from' || '' ); $subject = $q->param( 'mail_subject' || '' ); $message = $q->param( 'html_message' || '' ); $headers = "Content-Type: text/html; charset=iso-8859-1\r\n"; $headers .= "MIME-Version: 1.0\r\n"; $headers .= "Content-Transfer-Encoding: 7bit\r\n"; print MAIL "To: $_\n"; print MAIL "From: $from\n"; print MAIL "Subject: $subject\n"; print MAIL '$headers'; print MAIL '$message'; } return close(MAIL);

    I think you meant :

    foreach (@address) { open MAIL,"|$mailprogram -t" or die "Can't open sendmail! ($!)"; $from = $q->param( 'mail_from' || '' ); $subject = $q->param( 'mail_subject' || '' ); $message = $q->param( 'html_message' || '' ); $headers = "Content-Type: text/html; charset=iso-8859-1\r\n"; $headers .= "MIME-Version: 1.0\r\n"; $headers .= "Content-Transfer-Encoding: 7bit\r\n"; print MAIL "To: $_\n"; print MAIL "From: $from\n"; print MAIL "Subject: $subject\n"; print MAIL '$headers'; print MAIL '$message'; close MAIL; }

    He who asks will be a fool for five minutes, but he who doesn't ask will remain a fool for life.

    Chady | http://chady.net/

      I initally had this in my code, but changed it after thinking that instead of opening the MAIL filehandle on every interation of the loop, I'd open MAIL once, loop thru all the addresses, then close the filehandle. Is that wrong?

      "Do or do not--there is no try." --Yoda
        Chady underestimates his grasp of the problem. Yes, the second and third emails are getting lost in some sort of HTML-mail muddle as useless additions to the body of the first email. You must close and re-open the sendmail pipe to send subsequent emails.

        Or include all three addresses on the "To:" line and send them all at once.

        ------------------------------------------------------------
        "Perl is a mess and that's good because the
        problem space is also a mess.
        " - Larry Wall

        I'm not really sure, but I think that you need to close sendmail so it can send the email, or else, it will keep on printing the text in the body of the current email, and that's why you're getting only the first email sent.. because the rest of the emails are just body in the first one.

        then again, I might be wrong.


        He who asks will be a fool for five minutes, but he who doesn't ask will remain a fool for life.

        Chady | http://chady.net/
Re: Sending HTML-formatted mail to a list
by belg4mit (Prior) on Dec 16, 2001 at 23:00 UTC
    You might try a supersearch, this recent node should be useful.

    --
    perl -p -e "s/(?:\w);([st])/'\$1/mg"

Re: Sending HTML-formatted mail to a list
by trs80 (Priest) on Jan 20, 2002 at 06:56 UTC