Skip to page content or Skip to Accesskey List.


Main Page Content

Simple Cgi Email Subroutine

Rated 3.91 (Ratings: 1)

Want more?

  • More articles in Code
Picture of MartinB

Martin Burns

Member info

User since: 26 Apr 1999

Articles written: 143

When I'm writing CGI programs, I find that many - if not most - need to send email at some point. Rather than rewrite a mailing routine every time, I produced a simple reuseable Perl subroutine. What you're about to see is a simplified version of it, for you to build on yourself if you like.

Here's the subroutine. You'll need to save it locally, rename it with a .pl file extension, and upload it to your webserver.

System requirements

You'll need 3 things:

  1. A Unix server. It won't work on NT, but it might on MacOSX Server.

  2. Access to Sendmail or an equivalent. Exim and qmail usually work just fine, but check with your sysadmin.

  3. Perl5. Perl4 *should* work, but I can't promise anything.

How to use it.

All you have to do is require the file, tell it where your Sendmail is, and call the subroutine with appropriate variables. Here's the most trivial example:


require '/path/to/';

$SENDMAIL = '/usr/bin/sendmail';

&simple;_sendmail('Hello!', '', '', 'Hello World');


The general format of the subroutine variables is:

subject, from, to, body, cc, bcc

The body, cc and bcc variables are completely optional, and you can either have each variable literally used as above (make sure you use single quotes, or your @ signs will cause trouble), or derived from variables:

&simple;_sendmail($subject, $from, $to, $body, $cc, $bcc);


  • This subroutine doesn't check the validity of email address formats. If you're deriving any address from user input, it's wise to add some validation.

  • This subroutine doesn't attach files or support HTML email.

  • You can only use one recipient in each of the from, cc and bcc fields.

None of these limitations is particularly taxing to rectify.

The routine

Let's step through it.

 67: sub simple_sendmail {

102: }

103: 1;

This is the bare outline of any subroutine. Because we're requiring the file, it works as if the file is part of the main script, so you don't need a #!usr/bin/perl line. All you have to do is ensure that it's in correct syntax, and the last line evaluates to true.

69: local($subject, $from, $to, $body, $cc, $bcc) = @_;

This grabs the incoming data (stored in the Perl special variable @_), and puts it into sensible variable names. Because we're using local variables, there won't be any problems if you've used $to (etc) in your main script.

73: open(MAIL, "|$SENDMAIL -t");

75: $| = 1;

This is the main engine of the script. Unix works in such a way that everything - programs included - can be considered as a file. So what we do here is open a connection to the 'file' that is the Sendmail program, and attach it to a filehandle, MAIL; just as if we were outputting to a real file. Line 75 ensures that each line will be dispatched as it's output, which will give a more reliable result.

80: print MAIL "To: $to


81: print MAIL "From: $from


82: print MAIL "CC: $cc

" if $cc;

83: print MAIL "BCC: $bcc

" if $bcc;

84: print MAIL "Subject: $subject


These are the functional headers, which tell the email where to go, who it's from, and what its subject is.

85: print MAIL "x-mailer: EasyWeb Design - email


86: print MAIL "x-copyright: simple_sendmail 1.0, Copyright (C) 1999 Martin Burns


87: print MAIL "x-license: GNU General Public License version 2


88: print MAIL "x-license_url:


If you've looked at our mail headers tutorial, you'll remember that any header which begins with x- is ours to play with. So I've used it to add an unobtrusive credit to myself for the routine. Most people won't notice it, but someone who's in a position to give you work just might. I've also put on the licensing info for the routine, so that anyone literate enough to be interested in how it's done can find out what restrictions I've put on its distribution.

I also use the x-mailer header - typically used by email clients - to distinguish incoming email from forms. As I receive a bcc from most forms I install for monitoring and diagnostic purposes, I can filter them into my deleted mail folder, where they sit for 24 hours before they're auto-deleted. My mail client (Claris Emailer) also colour codes them for me, so it's easy to keep an eye what's going on.

The other important thing to notice is that, while most of the other headers end with a line-break to separate them, the last one ends with two. This is how mail clients know where the headers end, and the message body begins - there's a blank line between the two.

Finally, we get to print the body of the message, if there is one:

93: if ($body) {

94:   print MAIL $body;

95: }

96: print MAIL "


And there's another blank line at the end.

The very last thing we need to do is close the file handle:

101: close(MAIL);

So there you have it - a simple, all-purpose mail subroutine.

Martin Burns has been doing this stuff since Netscape 1.0 days. Starting with the communication ends that online media support, he moved back through design, HTML and server-side code. Then he got into running the whole show. These days he's working for these people as a Project Manager, and still thinks (nearly 6 years on) it's a hell of a lot better than working for a dot-com. In his Copious Free Time™, he helps out running a Cloth Nappies online store.

Amongst his favourite things is ZopeDrupal, which he uses to run his personal site. He's starting to (re)gain a sneaking regard for ECMAscript since the arrival of unobtrusive scripting.

He's been a member of since the very early days, a board member, a president, a writer and even contributed a modest amount of template code for the current site. Above all, he likes to do things because it knowingly chooses to do so, rather than randomly stumbling into them. He's also one of the boys and girls who beervolts in the UK, although the arrival of small children in his life have knocked the frequency for 6.

Most likely to ask: Why would a client pay you to do that?

Least likely to ask: Why isn't that navigation frame in Flash?

The access keys for this page are: ALT (Control on a Mac) plus: is an all-volunteer resource for web developers made up of a discussion list, a browser archive, and member-submitted articles. This article is the property of its author, please do not redistribute or use elsewhere without checking with the author.