in reply to CGI form to email

The following script is one that I use occasionally when I need a self-mailer. It is self-contained: a single script outputs the HTML form, takes the input, and outputs the success/failure page. It takes the precaution of not accepting the recipient's email address via the form. Accepting recipient email addresses via an HTML form exposes you to malicious people creating their own clients that will interact with your script to turn it into a spam relay. This script won't let that happen (I'm fairly certain).

I wrote it pretty early on in my Perl learning curve, so I apologize in advance for any inelegance.

In particular, if I had it to do over again, I would have written this using MIME::Lite. I've gotten so that I prefer it over Mail::Mailer. But as they say in Portuguese, "Tanto faz" (either will do).

I would also do away with the CGI::Carp stuff after the development phase was overwith.

I also wrote this before I understood HTML::Template, so it reads header and footer files to allow for poor-man's site templates.

Again, if I were rewriting it, I would do a lot more to separate the HTML from the code.

But notwithstanding those caviets, look at it as a good starting point. It gets the job done for me when my needs are fairly simple... Here it is: selfmailer.cgi.

use strict; use warnings; use CGI qw( -unique_headers ); use CGI::Carp qw( fatalsToBrowser ); use Mail::Mailer; my $recipient_email = 'someone@anywhere.org'; my $recipient_name = 'John Doe'; my $doc_title = "Contact".$recipient_name; my $script = "selfmailer.cgi"; my ($top_form, $bottom_form); BEGIN { my ($tof_file, $bof_file) = ( '', '../site_templates/bof.shtml' ); my @templates; foreach ($tof_file, $bof_file) { if ( $_ ) { my $fh; local $/ = undef; open $fh, "<$_" or die "Can't open $_: $!\n"; my $template = <$fh>; close $fh or die "Can't close $_: $!\n"; push @templates, $template; } else { push @templates, ''; } } ($top_form, $bottom_form) = @templates; sub carp_error { my $error_message = shift; my $err = new CGI; print $err->header( "text/html" ), $err->start_html( "Error" ), $err->h1 ( "Error" ), $err->p( "Sorry, the following error occurred: "), $err->p( $err->i( $error_message ) ), $err->br, $err->p( $bottom_form ), $err->end_html; } CGI::Carp::set_message( \&carp_error ); } $ENV{PATH} = ''; my $q = new CGI; SWITCH: { !$q->param() && do { print_mail_form( $q, $doc_title, $recipient_name, $bottom_form ); last SWITCH; }; $q->param('Send') && do { if ( validate_input($q) ) { send_message( $q, $recipient_email, $q->param("Sender"), $q->param("From"), $q->param("Subject"), $q->param("Message") ); success ( $q, $bottom_form, $recipient_name ); } else { output_error( $q, $doc_title, "All fields must be filled in.", $bottom_form ); } last SWITCH; }; output_error( $q, $doc_title, "Unrecognized form data.", $bottom_form ); } $q->delete_all(); sub print_mail_form { my ( $q, $title, $recipient, $bof ) = @_; print $q->header( "text/html" ), $q->start_html( $title ), $q->h1( $title ), $q->hr, $q->p( "You may use this form to send an email message +", "to $recipient. Please include your name and ", "email address." ), $q->start_form( -action => $q->url(), -method => "POST" ), $q->p( "Name: ", $q->textfield( -name => "Sender", -size => 20, -maxlength => 40)), $q->p( "Email Address: ", $q->textfield( -name => "From", -size => 40, -maxlength => 80 )), $q->p( "Subject: ", $q->textfield( -name => "Subject", -size => 60, -maxlength =>80 ) ), $q->p( "Message:" ), $q->textarea( -name => "Message", -cols => 60, -rows => 16 ), $q->submit( -name => "Send", -value => "Send" ), $q->reset(), $q->p( $bof ), $q->end_html; } sub output_error { my ( $q, $title, $text, $bof ) = @_; print $q->header( "text/html" ), $q->start_html( "$title Error" ), $q->h1( "Error:" ), $q->br, $q->p( "The $title form encountered an error." ), $q->p( $text ), $q->p( "If you wish you may ", $q->a( { -href => $q->url() }, "return to the mailer." )), $q->p( $bof ), $q->end_html; } sub validate_input { my $q = shift; foreach my $parameter ( 'Sender', 'From', 'Subject', 'Message' ) { return 0 if not $q->param( $parameter ); my $param = $q->param($_); if ( $_ eq 'From' ) { $param =~ s/[~`#]//; $q->param($_,$param); } } return 1; } sub send_message { my ( $q, $recipient_addr, $sender_name, $sender_email, $subject, $message ) = @_; my $mail = new Mail::Mailer; $mail->open( { To => $recipient_addr, From => $sender_email, Subject => "[Perlmonk Contact] " . $subject } ) or die "Can't open mail transport system: $!\n"; print $mail $message; close $mail or die "Can't close mail transport session: $!\n"; } sub success { my ( $q, $bof, $recipient_name )= @_; print $q->header( "text/html" ), $q->start_html( "Success" ), $q->h1("Success"), $q->h3("Here is how your message appeared."), $q->p("To: $recipient_name"), $q->p("From: ",$q->param('Sender')," <", $q->param('From'),">"), $q->p("Subject: [Perlmonk Contact] ", $q->param('Subject')), $q->p("Message:",$q->br, $q->param('Message')), $q->p($bof), $q->end_html; }

For an example of this script in use, you may visit http://davido.perlmonk.org/cgi-bin/selfmailer.cgi


Dave

Replies are listed 'Best First'.
Re^2: CGI form to email - with mailx?
by monkfan (Curate) on May 17, 2006 at 16:42 UTC
    Dear davido,

    I am sorry to have to intrude you back again after this wonderful old post of yours.
    First of all can you enable the above script again from your server? Since when I tried it here, it gave error.

    I think because it fail to recognize this line:
    my ( $tof_file, $bof_file ) = ( '', '../site_templates/bof.shtml' );
    I have the similar problem with OP. The following script does a simple processing. It try to send the input values by email. Initially with "mailx" command under linux, then with Mail::Mailer as you suggested.

    But why my script below fail to send the email?
    The script below also accessible in the following site:
    __BEGIN__ #!/usr/bin/perl -wT use CGI ':standard'; use Data::Dumper; print header, start_html('Order Ice Cream with Price'), h1('Order Ice Cream with Price'); generate_form(); print_results() if param(); print end_html(); sub print_results { print b('Customer name: '), param('customer'), br; my $ct = param('cone'); my $nu = param('no_unit'); my $uemail = param('user_email'); my $subject = "Result"; if ( $ct && $nu ) { my $content = "You ordered $ct as many as $nu unit"; print $content,br; print "This message should be sent to your email address: ",u( +$uemail), " soon"; # Tried to send email here, but fail... # system("mailx -s $subject $uemail < $content"); # Tried this to send email also fail... # It says can't find module, but in my server # I have no problem doing: perl -c mailresult.cgi send_message( $uemail, "monkfan", "ewijaya\@i2r.a-star.edu.sg", $subject, $content ); } else { show_error_message(); } } sub send_message { # I deliberately remove $q here my ( $recipient_addr, $sender_name, $sender_email, $subject, $message ) = @_; my $mail = new Mail::Mailer; $mail->open( { To => $recipient_addr, From => $sender_email, Subject => "[Perlmonk Contact] " . $subject } ) or die "Can't open mail transport system: $!\n"; print $mail $message; close $mail or die "Can't close mail transport session: $!\n"; } sub show_error_message { print "Unit Too Large\n"; } sub generate_form { print hr, start_form, strong('Your name : '), textfield( -name => 'customer' ), br,br strong('Your email: '), textfield( -name => 'user_email'), br,br strong('Cone: '), radio_group( -name => 'cone', -multiple => 1, -values => [qw/sugar waffle/]),br,br strong('Number of Units: '), textfield( -name => 'no_unit'), br,br submit( -value => 'Send Order' ), end_form, hr; } __END__

    Regards,
    Edward