PDA

View Full Version : multipart/alternative text/html email


Opally
08-20-2007, 10:44 PM
Hi!

I have some old Perl/CGI scripts I've been using to parse forms, send email, and write data to a file.

I'd like to have an option to display email content in a table, but my email sender only works with plain text, although it seems to be compatible with HTML and multipart/alternative email.

If I don't do multipart/alternative, and just force the HTML, I get HTML markup angle brackets, not HTML formatted mail.

If I try multipart/alternative as I am trying below, that does not send at all, it doesn't generate an error, either, nor does it get logged to my mail log as undeliverable. (by the way, someone in this forum recommended using
use CGI::Carp qw/fatalsToBrowser/;
and I say THANK YOU! A huge help in debugging.)

I've attached the mail-lib.pl script which processes the email for sendmail.

Below is the part of my email formatting script that tries to do HTML.

Does this look about right to you, to format a multipart/alternative email?

if ($should_i_mail eq "yes")
{
$current_date = &get_date;
$email_body = "MIME-Version: 1.0";
$email_body .= "Content-Type: multipart/alternative\; boundary=\"_jkkdsffds32432dlkjifewks_\"";
$email_body .= "--_jkkdsffds32432dlkjifewks_";
$email_body .= "Content-Type: text/html\;charset=\"iso-8859-1\"";
$email_body .= "Content-Transfer-Encoding\: 8bit";
$email_body .="\<html\>\<head\>";
$email_body .="\</head\>";
$email_body .="\<body\>";
$email_body .="\<body style=\"font-family:courier\"\>";
$email_body .= "Content-Transfer-Encoding: 8bit";
$email_body .= "On $current_date, the following data was submitted from $ENV{'HTTP_REFERER'}";
$email_body .= "\n\n";

$email_body .= "\<table\>";


foreach $variable (@form_variables)
{
$form_data{$variable} =~ s/&quot;/"/g;
$form_data{$variable} =~ s/&lt;/\</g;
$form_data{$variable} =~ s/&gt;/\>/g;
$form_data{$variable} =~ s/\<P\>/\n/g;

if ($form_data{$variable}!= ""){
$email_body .= "\<tr\>";
$email_body .= "\<td\>";
$email_body .= &format_text_field($form_variable_name_map{$variable});
$email_body .= "\<\/td\>\<td\>";
$email_body .= "$form_data{$variable}";
$email_body .= "\<\/td\>\<\/tr\>";

}
}

$email_body .= "\</table\>";
$email_body .= "\</body\>\</html\>";
$email_body .= "--_jkkdsffds32432dlkjifewks_";
$email_body .= "Content-Type: text/plain\; charset=\"iso-8859-1\"";
$email_body .= "Plain text content should be here";
$email_body .= "--_jkkdsffds32432dlkjifewks_--";

if ($form_data{'mailto'} ne "")
{
$email_to = $form_data{'mailto'};
}

# Finally, the script uses the send_mail routine in
# mail-lib.pl to send the data. The send_mail routine
# takes 6 parameters, all of which have already been
# defined and explained.

&send_mail("$email_of_sender","$email_to", "$email_subject", "$email_body");

} # End of if ($should_i_mail eq "yes")

Would love to hear some feedback on what might not be working here.

These scripts are ancient, yes, just look at that date on mail-lib.pl. However, everything I've got right now works with them.

---Opally

nkrgupta
08-21-2007, 07:08 AM
Hi,

If you are not averse to having a clean, robust, scalable and secure code, and don't mind putting in a little effort to customise it to your needs, then please download a copy of the Form Mail script from http://nms-cgi.sourceforge.net/scripts.shtml . You will be able to do all that you require and much more, with a little editing. It's the best one available.

Naveen

Opally
08-21-2007, 03:50 PM
Thanks for the reply, Naveen.

I have used NMS Form Mail before, and have used the long version, and have been disappointed with the frequency of spam since it's a popular application, and so hackers easily find and exploit it. Yes, I've renamed the files many times, but their bots quickly figure it out. I'd have to add CAPTCHA to make it bearable, something I don't want to do with long forms. My forms have a CGI script action instead of a Perl script action, and I consider that to be an advantage.

That being said, I may take another look at whether it can suit my needs. My scripts include setup files with most configurable settings for each form, a form processor script, of which you saw a snippet, which handles results presentation and preparation, and some library scripts which prep the data for sendmail.

I'm hoping a CGI/Perl guru can tell me something specific about HTML formatted email and give me some idea why it's not working in this case, or ideas about where to look in a script when there are no obvious errors in syntax.

---Opally

FishMonger
08-21-2007, 05:24 PM
The most common method used for sending (plain text or HTML) email is to use the MIME::Lite module.

http://search.cpan.org/~yves/MIME-Lite-3.01/lib/MIME/Lite.pm#Send_an_HTML_document..._with_images_included!

FishMonger
08-21-2007, 05:28 PM
I have used NMS Form Mail before, and have used the long version, and have been disappointed with the frequency of spam since it's a popular application, and so hackers easily find and exploit it.
I think you're confusing the nms script with Matt's (scriptarchive) or you miss configured the nms script and/or still had some insecure hidden fields in your forms.

Opally
08-21-2007, 06:01 PM
I read everything I could find about how to properly and securely configure NMS formmail, including renaming the form processor file itself. I used both the compact version and the modular version. It wasn't that the form was being hijacked, it's that the designated form recipients were getting bot-generated spam. NMS formmail is so popular that the bots look for the form action, find
the .pl file, and automate form submissions. I've never had that happen with my current forms. They are not vulnerable to being hijacked, the email addresses cannot be retrieved by attempts to read scripts, and they are sufficiently uncommon that no bots are scripted for them. (not to mention that there is heavy field validation and stripping of code before submission.)

I'm basically happy with what I'm using, it's just not handling HTML email, and I don't see why. I don't know why the code snippet in my first post doesn't work, no Perl syntax errors turned up in Carp, but it just doesn't send, and I wonder if the mail-lib.pl script (the attached zip) is the key. I'm hoping that someone familiar with HTML email and Perl can give that attachment a quick scan and see if there's something about it that's preventing HTML email, OR, if there's something else I should be looking at.

The attachment is short, if you prefer that I paste in the code, I can do that instead, let me know, I can imagine that some people prefer not to open attachments.

For instance, do I need a header parameter for generating HTML email?

or is adding email headers extraneous to sendmail protocol?

Apart from the fact that I'm not using NMS formmail, am I completely "out to lunch"?

thanks again for the replies!!!

---Opally

P.S. I'm taking a look at MIME Lite and seeing if I can more or less easily plug it in with the rest of my form processing scripts.

FishMonger
08-21-2007, 06:23 PM
Your first step should be to drop the mail-lib.pl script and instead use the MIME::Lite module. As a mail "module", that mail-lib script is a joke.

Let the MIME::Lite module worry about the headers, all you need is to put the html body portion into a var and (via a here document if you wish) and then attach it to the email. The link I posted give an example of the proper syntax.

If you need, I can give you a more complete example using your data.

Opally
08-21-2007, 06:27 PM
The most common method used for sending (plain text or HTML) email is to use the MIME::Lite module.

http://search.cpan.org/~yves/MIME-Lite-3.01/lib/MIME/Lite.pm#Send_an_HTML_document..._with_images_included!

Looks really good. Because I am a very ignorant coder, can you point me to an example of how MIME::Lite would be used with a form, or a form processor script? (I see that my web host already has this module installed!)

I see that it is an email preparer, like my mail-lib.pl, but that this is vastly better.

---Opally

FishMonger
08-21-2007, 06:55 PM
Post you current form processing script as an attachment and I'll take a look at it.

Opally
08-21-2007, 07:43 PM
you're a dear :)
I really do appreciate being able to learn from you guys!

included in the attached zip:


cgi-bin/form_processor_testhtmlemail.cgi
cgi-bin/Setup_files/htmlemailtest.setup
cgi-bin/Library/mail-lib.pl
cgi-bin/Library/cgi-lib.pl


the form can be seen in action here (http://www.coreknowledge.org/secure/html_forms/htmlemailtest.php).

The form delivers its contents to the cgi by way of the hidden setup field.
<FORM METHOD="POST"
ACTION="../cgi-bin/form_processor_testhtmlemail.cgi"
ENCTYPE="x-www-form-encoded" name="infoform" id="infoform">

<INPUT TYPE="hidden" NAME="setup_file" VALUE="htmlemailtest.setup">

--Opally

FishMonger
08-22-2007, 10:25 AM
I've taken a look at each of the files and here's my input.

As I've already mentioned, the mail-lib script should be dumped.

The cgi-lib.pl script has been depreciated for almost 10 years and has been superseded by the CGI module which is considered the de facto standard module for writing Perl cgi scripts. If you take a look at it, you'll see that it's far superior to the cgi-lib script. http://search.cpan.org/~lds/CGI.pm-3.29/CGI.pm

Besides the issue of the form_processor_testhtmlemail.cgi script using the cgi-lib script in instead of the CGI module, the script is also using some other questionable code.

My best recommendation is to start over and either find a more up-to-date email form processor script or start from scratch and write your own. The nms FormMail script is actually pretty secure if used correctly, but since you don't seam to like it, my next recommendation would be the TFMail which is also from the nms project. I haven't used it myself, but it is written well and it looks like it should send the html email without much trouble.

FishMonger
08-22-2007, 06:20 PM
I can't devote the time needed to fix all of the problems with your scripts, but here are a few adjustments you can make to be able to send the html email.

Add the MIME::Lite module to the beginning of your form_processor_testhtmlemail.cgi script.use MIME::Lite;

Remove these lines.
$email_body = "MIME-Version: 1.0";
$email_body .= "Content-Type: multipart/alternative\; boundary=\"_jkkdsffds32432dlkjifewks_\"";
$email_body .= "--_jkkdsffds32432dlkjifewks_";
$email_body .= "Content-Type: text/html\;charset=\"iso-8859-1\"";
$email_body .= "Content-Transfer-Encoding\: 8bit";
$email_body .="\<html\>\<head\>";
$email_body .="\</head\>";
$email_body .="\<body\>";

Replace this line: &send_mail("$email_of_sender","$email_to", "$email_subject", "$email_body");
with this:$msg = MIME::Lite->new(
To =>$email_to,
From =>$email_of_sender,
Subject =>$email_subject,
Type =>'multipart/related'
);

$msg->attach(Type => 'text/html',
Data => $email_body
);

$msg->send;
You may still need to do some testing/debugging but it should get you close.

Opally
08-22-2007, 10:08 PM
thank you for the help, code improvements, and recommendations!!

I'm making progress!

I am still wondering how to make it multipart.

The way you've shown me generates an HTML email, correct? (that's what I'm generating.)

Where do I stick the plain text part unless I'm using those multipart divider strings and declaring the divider string in the header...?

--Opally

Opally
08-23-2007, 05:16 PM
I've broken up my email thus, but it's creating attachments, it's not a true multipart/alternative email... does such a thing not exist?

$msg = MIME::Lite->new(
To =>$email_to,
From =>$email_of_sender,
Subject =>$email_subject,
Type =>'multipart/alternative',
Type => 'text/plain',
Data => $email_body
);

$msg->attach(Type => 'text/html',
Data => $email_html
);

$msg->send;

I am reading the documentation on MIME::Lite (http://search.cpan.org/~yves/MIME-Lite-3.01/lib/MIME/Lite.pm) but I don't see an example of multipart/alternative, just multipart/related.

---Opally

Opally
08-23-2007, 05:28 PM
omg I got it!!! Happy, happy! Joy, joy! :thumbsup:

$msg = MIME::Lite->new(
To =>$email_to,
From =>$email_of_sender,
Subject =>$email_subject,
Type =>'multipart/alternative'
);

$msg->attach(Type => 'text/plain',
Data => $email_body
);

$msg->attach(Type => 'text/html',
Data => $email_html
);
$msg->send;


Found the answer here (http://www.perlmonks.org/?node_id=525001).

Thank you, Fishmonger, for your help!

(Maybe you'd be willing have a peek at my efforts to use cgi.pm instead of my deprecated form processor script...?)

---Opally