|
�
|
Sending email using perl and sendmail.
A very common task for a cgi script is to be able to inform a set of users with
data generated by itself or other programs, cgi's or not. For example, you might
be one of the web designers who have joined one of the myriad of free counter
programs on the internet that email you with nice statistics and reports about
your web pages' traffic. Systems like that are responsible for informing such
a large number subscribers that sending the reports manually would require a
full-time employee devoted to this task only. Obviously this wouldn't be a sensible
option even for a relatively large organization.
The way to automate this task is to let a perl program do those tedious bits
of work for you. In this article we will build a perl script which does exactly
that. We are going to go step by step giving explanations and analyzing the tricky
parts.
Perl, being perl, provides the programmer with more than one ways to do same
thing, sending email included. In this script we are going to use sendmail. Sendmail,
is an open source program used on most unix computers and some nt workstations
as well. Sendmail as its name implies has the ability to send email! We are going
to use perl's ability to open pipes to programs to run sendmail and feed it with
input. If you are not familiar with sendmail it doesn't really matter though;
you should just understand that sendmail is able to send an email, with its headers
and content, to your mail gateway which will in turn forward it to its recipient(s).
Here is a very simple program that emails a confirmation to a user that his/her
request to subscribe to a newsletter has been accepted:
#!/usr/bin/perl -w
use strict;
use CGI;
use Email::Valid;
my $query = new CGI;
# it is important to check the validity of the email address
# supplied by the user both to catch genuine (mis-)typing errors
# but also to avoid exploitation by malicious users who could
# pass arbitrary strings to sendmail through the "send_to"
# CGI parameter - including whole email messages
unless (Email::Valid->address($query->param('send_to'))) {
print $query->header;
print "You supplied an invalid email address.";
exit;
}
my $sendmail = "/usr/sbin/sendmail -t";
my $reply_to = "Reply-to: foo\@bar.org\n";
my $subject = "Subject: Confirmation of your submission\n";
my $content = "Thanks for your submission.";
my $to = $query->param('send_to')."\n";
my $file = "subscribers.txt";
unless ($to) {
print $query->header;
print "Please fill in your email and try again";
}
open (FILE, ">>$file") or die "Cannot open $file: $!";
print $to,"\n";
close(FILE);
my $send_to = "To: ".$query->param('send_to');
open(SENDMAIL, "|$sendmail") or die "Cannot open $sendmail: $!";
print SENDMAIL $reply_to;
print SENDMAIL $subject;
print SENDMAIL $send_to;
print SENDMAIL "Content-type: text/plain\n\n";
print SENDMAIL $content;
close(SENDMAIL);
print $query->header;
print "Confirmation of your submission will be emailed to you.";
A note about security
Before attempting to explain how the script works here is an important
security note: always validate user supplied input. In the case of our CGI
mailer the "send_to" parameter comes from a user submitted form
and hence could be exploited by a malicious party to pass arbitrary
arguments to the sendmail program. To avoid this hazard we utilize
the Email::Address module from CPAN to check the
conformance of the supplied email address. If the address is invalid -
because of a genuine typing error or an exploitation attempt - we return an
error message. Otherwise, we proceed with emailing the confirmation using
the technique described in the rest of this article.
How the script works
At first glance you can notice that this a relatively small program which if
it wasn't that verbose would be even smaller. Looking through it you will also
see that it is very simple to understand even for the Perl beginner; however
it more than fullfils the task of sending email.
Let's have a look at it line by line... The cgi script takes its input from a
web form. This hypothetical form consists one text input field:
<FORM method="POST" action="http://perlfect.com/cgi-perlfect/cgimail.pl">
<INPUT type="text" name="send_to">
<INPUT type="submit">
</FORM>
The script uses the CGI.pm module to parse the form data. If you are not familiar
with that module I suggest that you read and learn about it as it will make you
life as a scripter a lot happier. The param() function provided by CGI.pm returns
the value of a form field given its name as an argument and that's all you need
to know for now; hence we use it in our script to find out what the user has
entered in the text box. If the user has not entered anything the script returns
an error message prompting the user to try again after filling in the appropriate
text field.
If the user has entered an email address this is appended to a text file for
later use by another program and then the script procedes to return a confirmation
email to the user.
An email message consists of some headers and the content. There are many standard
headers but the ones you will most commonly encounter and the one we use here
are:
| To: |
A comma separated list of recipient addresses. |
| From: |
The email address of the sender. |
| Reply-to: |
The email address to whic replies should be sent. |
| Subject: |
The subject of the message. |
| Content-type: |
The MIME type of the content. |
The headers precede the content of the message. The content type header is written
just before the content and is followed by two newline characters.
Sendmail has the ability, as most unix programs, to read from standard input
hence all we need to do is a open a pipe to it and provide it with the input
we want it to process. You will notice that we have given the -t option to sendmail.
This merely tells sendmail to scan the message for a To:, Cc: or Bcc: header
and extract the list of recipients from there. Having opened the pipe succesfully
we print the message to it. First the headers, each one followed by a newline
character, the a newline by itself and finally the content of the message. Finally
we close the pipe. The email has been succesfully sent!
Here is a list of useful things you can do by using sendmail and perl:
- Inform visitors of your site that have asked, that your site has been updated.
The script used as an example here would be a good way to collect the addresses
of the people you want to email.
- Inform yourself of the way your scripts are running. For example you can
write a few lines of code that email you when something goes wrong in a script
that you 've written.
- Create an online mailing list.
These are only some of the things you can do, but there is one thing you shouldn't
do, except if you are really nasty. That is, do not spam people. Never email
people that have not asked for the information you are providing as it will probably
make them angry and in the future they will ignore any that corespondence from
you. Have fun and be polite!
Online Documentation/Tutorials
- Your sendmail program's man pages will provide more detailed info about
sending mail.
-
Computing Securely, a collection of security tips
from Randal L. Schwatz.
- You might want to have a look at the documentation of the Mail:: modules
available at CPAN. There are also
many other modules for sending and processing mail there.
Comments
[an error occurred while processing this directive]
|
Suggested Reading
The Perl Cookbook is full of quick solutions to everyday programming
problems in perl with explanations and tips easy to understand even for
beginners, but also frequently useful even to more experienced programmers.
The code is clear and straightforward and the topics covered as well-thought
and correspond to real world examples, so frequently you can literally
copy code snippets from the book and fit them in your program. It is
a nice complement for the Camel
Book on your bookshelf.
[an error occurred while processing this directive]
|