Quick Search for:  in language:    
CGI,send,plain,multipart,emails,from,within,P
   Code/Articles » |  Newest/Best » |  Community » |  Jobs » |  Other » |  Goto » | 
CategoriesSearch Newest CodeCoding ContestCode of the DayAsk A ProJobsUpload
Perl Stats

 Code: 74,273. lines
 Jobs: 24. postings

 How to support the site

 
Sponsored by:

 
You are in:
 

Does your code think in ink?
Login





Latest Code Ticker for Perl.
Click here to see a screenshot of this code!CGIScripter
By David Simpson on 11/24

(Screen Shot)

Calender
By Jeff Mills on 11/20


quikpoll
By Jeff Mills on 11/20


Encrypt Password
By Jeff Mills on 11/20


Rock, Paper, Scissors w/ GUI
By Kurt Rudolph on 11/19


Click here to put this ticker on your site!


Add this ticker to your desktop!


Daily Code Email
To join the 'Code of the Day' Mailing List click here!

Affiliate Sites



 
 
   

Sending e-mails from Perl CGI script

Print
Email
 

Submitted on: 5/31/2001 12:40:42 AM
By: Serge  
Level: Advanced
User Rating: By 4 Users
Compatibility:5.0 (all versions)

Users have accessed this article 13501 times.
 
(About the author)
 
     How to send plain or multipart e-mails from within Perl CGI script.

 
 
Terms of Agreement:   
By using this article, you agree to the following terms...   
1) You may use this article in your own programs (and may compile it into a program and distribute it in compiled format for languages that allow it) freely and with no charge.   
2) You MAY NOT redistribute this article (for example to a web site) without written permission from the original author. Failure to do so is a violation of copyright laws.   
3) You may link to this article from another website, but ONLY if it is not wrapped in a frame. 
4) You will abide by any additional copyright restrictions which the author may have placed in the article or article's description.

 

Introduction

Sending e-mail from Perl-based CGIs appears to be one of most difficult tasks for newbies. Probably most asked question about sending e-mail is: 'how do I send e-mail from my CGI script, plain one or along with attachment?' This question becomes so important these times, whether you have to send automated sign-up confirmation or newsletter.

As with almost any task, there are already some solutions around. To send e-mail, you could use wide range of tools, like using appropriate Perl module or send message directly using server's MTA (Mail Transport Agent, such as 'sendmail' for Un*x or 'blat' for NT), or even consider to write low-level SMTP subroutine yourself.

In this article I'll concern on common usage of MIME::Lite module to send e-mails, because it easy to use, takes much less requirements than full-weight Big Brother called MIME::Tools and doesn't require lot of wrapping.
 

Availability

First, make sure you have MIME::Lite module installed at your host. Unfortunately, at this time not so many webhosts have MIME::Lite pre-installed. Contact your tech support service or host administrator regarding these matters. If installation is impossible, you still be able to use the module, but you need obtain it first.
 

Obtaining the MIME::Lite

The easiest way to get the latest version of MIME::Lite is to get it from CPAN, or Comprehensive Perl Archive Network (http://www.cpan.org). If you'll do, you'll have so-called 'module distribution' - gzipped tar archive file (*.tar.gz or *.tgz). Once you've got it, you are ready to install.
 

Module installation

You can install MIME::Lite in two ways. First way assumes that you have shell access to your host. Second way is much more simple and is recommended if you have non-Un*x host, or have no idea what the Un*x shells about, or just won't spend the time.
 

Installation via shell

Ok, so you want to install MIME::Lite using your shell access. I assume that you have no root access to remote host (I bet it your case unless you rent the dedicated server ;). Upload the module distribution to your host, somewhere outside of the website tree (e.g. outside of 'public_html' or 'www') directory, log into the shell, change to directory where you have upload the distribution then type:

   tar zxf module_name

or, if your 'tar' does not support 'z' option, try

   gzip -dc module_name | tar xf -

, where 'module_name' is the full filename of distribution, including file extension. Do not forget about the case-sensitivity. When tar finished, you should have there newly created directory, which has the name similar to those of distribution filename but without extension. Change to the this directory. There should be a file called Makefile.PL or like. Type:

   mkdir /myaccount/final_dir
   perl Makefile.PL PREFIX=/myaccount/final_dir
   make install

, where '/myaccount/final_dir' stands for full path to directory where you want install module to. Module should be installed. If you have any problems, please read module documentation, contact your support staff or just make the plain installation instead.

In case if you have the root access or, more generally, you are granted to install module in system-wide directories and want to do so, just don't provide PREFIX in example above.
 

Plain installation

Plain installation is the simplest way to use MIME::Lite if it isn't installed yet. Unzip the module distribution using archiver like WinZip, take the Lite.pm and upload it (don't forget to use FTP in ASCII mode) along with your CGI scripts. Make sure the permissions for Lite.pm are 0644 (rw-r--r--).
 

Using the Module

As with any Perl module, in order to use MIME::Lite from within your Perl CGI scripts, you have to include it:

   use MIME::Lite;

If module is installed by yourself (no matter using shell or not), before this line you need either

   use lib '/myaccount/final_dir';

or

   use lib '/myaccount/final_dir/lib/site_perl';
 

Composing And Sending Simple E-mail Messages

Before proceeding, I assume that you already have MIME::Lite installed and ready to use. Also, I assume that you already know some e-mail basics.

Process of sending e-mail consists of two parts: composing e-mail then sending it. Well, let's dive:

#!/usr/bin/perl

# You may want to add 'use lib...' before
# this line, according to your situation
use MIME::Lite;

# if your Perl runs on non-Un*x OS, you may need to set $WIN_NT to
# non-zero value here.
undef $WIN_NT;

# set up MTA (mail transfer agent, e.g. sendmail)

if($WIN_NT) {
        # Suitable for non-Un*x environment
or if you just want to use SMTP
        MIME::Lite->send('smtp', "smtp.myisp.net");
} else {
        # set up your MTA here
(you can try just MIME::Lite->send('sendmail') )
        MIME::Lite->send('sendmail', "/usr/sbin/sendmail -t -i");
}

# create the message body

my $body = qq|Hi!

This is a simple message.
Bye...
|;

# create message object and automatically compose new message

my $msg = MIME::Lite->new(
        From    =>'my@myhost.com',
        To      =>'you@yourhost.com',
        Subject  =>'Hi!',
        Data    => $body
);

# after composing, send message using MTA pre-defined above

die "Error sending e-mail: $!" unless $msg->send;

# compose another message

$msg = MIME::Lite->build(
        From    =>'my@myhost.com',
        To      =>'another@friend',
        Subject  =>'Hi too!',
        Data    => $body
);

# Save another message to the file rather than send it

open(FH, ">message.txt") or die("Couldn't create: $!");
flock(FH, 2) unless $WIN_NT;
$msg->print(\*FH);
close FH;

# print result

print "Content-Type: text/html\n\n";
print "Messages processed!";

# Gear down

exit(0);

In example above, first thing you made is set up method of sending: using MTA or over SMTP link. For Un*x or Linux systems, it's better to use MTA like sendmail. For NT or, generally, non-Un*x systems you'd better rely not on existence of system-specific MTAs (like 'blat' for NT) but instead use direct SMTP connection whenever possible.

Some commonly used command-line arguments for sendmail are:

-t scans message for fields To:, Cc: and Bcc: . The Bcc: line will be deleted before transmission.

-i (or -oi) ignores dots alone on lines by themselves in messages. (normally, such dot is message terminator.)

-oem returns back the message on error, according to address in the header.

After you've set method of sending, you have to construct new e-mail message object and build new message, giving it's header data (parameters like 'From', 'To' and so on) and message body ('Data'). This is done by calling new().

When you create or initialize $msg object, 'Data's value should contain message body. You can feed the string or the array of message lines. In case of array it will be concatenated.

After message object constructed, you can send your message immediately using send() method of the message object. To compose another message using existing MIME::Lite object, just re-initialize it - use build() instead of new().
 

Composing And Sending Complex E-mail Messages

What about sending e-mail in non-latin or even non-ASCII characters?... What about multipart message, e.g. with JPEG or PDF attached? In these cases, message and attachments should be properly encoded and linked together to avoid corruption in transit. Fortunately, MIME::Lite handles all of it, and we'll discuss these issues below.
 

Message encoding

In order to transmit message uncorrupted, you need to encode it according to standards. Following standard common encodings available:

* '7bit', or 'send as is'. Plain encoding for plain text. This encoding seems to be default for lot of current mail gateways, MTAs and mail clients. Line of message cannot exceed 1000 characters, including CRLF terminator.

* '8bit', or 'bit more advanced' ;) The same 7bit restrictions apply to this encoding too except that here you can use 8-bit characters. It could be useful for messages contain non-latin characters.

* 'binary', the same as 8bit but now message body lines may exceed limit of 1000 characters. However, message encoded that way is the first candidate to be corrupted when passed through mail gateways.

* 'quoted-printable', another standard encoding. It also deals with 8-bit data and has not line length limits.

* 'base64', widely used to encode. It fits the data into printable ASCII characters, so the message becomes bigger in size.

Below is quick guide for encoding:
 
Use encoding If your message contains
7bit Only 7-bit text, all lines less than 1000 characters
8bit 8-bit text, all lines less than 1000 characters
binary 8-bit text, long lines allowed
quoted-printable The same as '8bit' or 'binary' but more reliable
base64 Large non-textual data: archives, pictures and so on

The 'binary' encoding is not recommended; instead, consider using one of the other encodings above. For 7bit, 8bit and binary no real encoding done at all. Note that MIME::Lite automatically chomps long (those over 1000 characters) lines in case of 7bit or 8bit encodings.
 

Message attachments

Message with attachment(s) is 'multipart' in nature, i.e. consists of several parts. Such message could be one of type 'multipart/mixed', 'multipart/related' and so on, depending on what you have to compose.

All the parts of multipart message (e.g. message body or attached files) could be merged in 'inline' or 'attachment' fashion. For 'inline' case, files are attached along with message's body and could appear for end-user right inside the message. Otherwise, they could appear as links to files after the message ends.

For each attachment, you need to provide its MIME type, depending on what this file contains (e.g. 'text/plain', 'image/jpeg' etc.) To help you keep the mind clear, two special values available in MIME::Lite, they are 'TEXT' (means 'text/plain') and 'BINARY' (means 'application/octet-stream'). If you can't guess what MIME type you need, use TEXT for text attachment, and BINARY for any other files.
 

Putting it all together

So, to compose message with JPEG picture as standalone (non-inline) attachment, you need construct the message like that:

# compose message first

my $msg = MIME::Lite->new(
        From    => 'me@myhost.com',
        To      => 'you@yourhost.com',
        Type    => 'TEXT',
        Subject => 'Picture for you',
        Data   => "Picture you need is here!"
);

# Second, attach JPEG picture

$msg->attach(
        Type     => 'image/jpeg',
        Path     => '/path/to/real_file_name.jpg', = nt>
        Filename => 'recommended_file_name.jpg',
        Encoding => 'base64',
        Disposition => 'attachment'
);

In example above, 'Encoding' contains name of encoding schema for this file, discussed far above. 'Filename' parameter is optional. It contains recommended filename for the recipient saving the attachment to disk. You only need this if the filename at the end of the "Path" is inadequate, or if you're using "Data" instead of "Path". You should not put any path information (slashes, backslashes etc.) in the 'Filename'.

If you want to send the text message containing picture which should appear right inside body's text:

my $msg = MIME::Lite->new(
        From    => 'me@myhost.com',
        To      => 'you@yourhost.com',
        Subject => 'A message with 3 parts',
        Type    => 'multipart/mixed'
);

# attach first part of body

$msg->attach(
        Type     => 'TEXT',
        Data     => "Image is below this line"< = /tt>
);

# insert GIF picture (has the same arguments as "new"):

$msg->attach(
        Type     => 'image/gif',
        Path     => 'smile.gif',
);

# complete the body - add the last part

$msg->attach(
        Type     => 'TEXT',
        Data     => "Image is above this line"< = /tt>
);

If you provide no 'Disposition', default will be "inline", like in last example.

Another common task is to send HTML page with pictures linked to it. Here's how to compose such a message:

# Create the message object and initialize it

my $msg = MIME::Lite->new(
        From    => 'me@myhost.com',
        To      => 'you@yourhost.com',
        Subject => 'HTML with in-line images!',
        Type    => 'multipart/related'
);

# Attach HTML page

$msg->attach(
        Type => 'text/html',
        Data => qq|
<body>
  Here's the image:
  <img src="cid:theimage.gif">
</body>
|
);

# Attach GIF image

$msg->attach(
        Type => 'image/gif',
        Id   => 'theimage.gif',
        Path => '/path/to/somefile.gif',
);

Note that in example above, optional parameter 'Id' been introduced. In this example, for reference to the GIF you should mention its 'Id'.
 

Other MIME::Lite Abilities

You have also many other options for e-mails created with MIME::Lite. It has rich set of features to help you deal with most real-life situations. You can specify your own custom header fields, compose the message using existing files or filehandles, and output the message or its parts to string, file or filehandle, rather than send it.
 

Specifying custom header fields

In addition to lot of pre-defined standard header fields, you may specify your own custom field in the header. To do that, just append trailing ':' to its name, like this:

my $msg = MIME::Lite->new(
        From      => 'my@myhost.com',
        To        => 'you@yourhost.com',
        'Custom:' => 'custom-field-content',
        Data      => "Just a message"
);
 

Using existing files or filehandles for composition

Instead of 'Data', you may provide 'Path' with path to file which contains message body:

my $msg = MIME::Lite->new(
        From     => 'my@myhost.com',
        To       => 'you@yfourhost.com',
        Path     => '/home/johnsmith/message.txt' = t>
);

, or already opened filehandle as value of 'FH' (which in this case goes instead of 'Path' or 'Data'):

my $msg = MIME::Lite->new(
        From     => 'my@myhost.com',
        To       => 'you@yourhost.com',
        Cc       => 'some@other.com, some@more.com',
        Subject  => 'Mail from opened file...',
        FH       => \*HANDLE
);

In case of filehandle, DO NOT close it before you make any mail output. Why? Because when you specify message bodies by 'FH' or 'Path', MIME::Lite does not try to open and read files or filehandles right now (as well as it doesn't try to encode any data) until print() method is invoked. This is why I told you do not close input filehandles. However, it does some kind of verification to ensure there's no broken paths around. If you won't use that pre-flight check, just set $MIME::Lite::AUTO_VERIFY variable to 0 (false) before any construction of mail object.

If you need read the content of file right now, not waiting for print() to commit, you should use ReadNow parameter:

my $msg = MIME::Lite->build(
        From     => 'my@myhost.com',
        To       => 'you@yourhost.com',
        Type     => 'x-gzip',
        Subject  => 'Tar archive, gzipped on-the-fly before sending',
        Path     => "gzip < /path/to/archive/thebal = l.tar |",
        ReadNow  => 1
);

If ReadNow is '1' (true), it will open the path and suck the contents in right now. You may need this feature when you work with external executable instead of plain file, i.e. one of Un*x commands (like 'gzip'), and you won't execute the command over and over again to output the messages. Be careful, however; several really big message objects constructed with ReadNow will consume lot of memory.

If you need to read file's contents but have the message object already constructed, consider read_now() method:

   $msg->read_now();

It works like ReadNow, i.e. forces data from the path or filehandle (as specified by build()) to be read immediately, but should be used for already existing message objects.

Regardless of what method you prefer, you'll get fatal exception if the open fails. Handling Perl's fatal exceptions is out of scope of this article; there are already many information around related to this topic.
 

Output message to string, file or filehandle

Instead of sending, you could output whole message (including all the headers) to a string:

        my $str = $msg->as_string;

You can output just the header to string:

        my $str = $msg->header_as_string;

Or message's encoded body:

        my $str = $msg->body_as_string;

Also you can output the message to existing filehandle (either plain file or even pipe to MTA):

        $msg->print(\*HANDLE);

Again, you can output just the header:

        $msg->print_header(\*HANDLE);

or just the encoded body:

        $msg->print_body(\*HANDLE);

Be aware that if you give the message body via 'FH' then try to print() a message two or more times, every next print() will confuse; only header will be printed. To avoid this, you have to explicitly rewind the filehandle before any subsequent print():

        $msg->print(\*OUT_HANDLE);  # first print
        $msg->resetfh(\*IN_HANDLE);  # rewind input filehandle
        $msg->print(\*OUT_HANDLE);  # another print

If resetfh() fails for buffered streams, consider to use sysseek():

        sysseek(\*IN_HANDLE, 0, 0);
 

Conclusion

In this article, I've tried to explain MIME::Lite and to describe most of its abilites. However, this is not complete description of MIME::Lite; for that, you should read accompanying documentation. As to other possibilites for sending e-mail (besides using of MIME::Lite), they are, probably, subject for my other articles. I appreciate your feedback and also I really need to know what the another topics you've interested in.
 

P.S. Sorry for possible HTML garbage, looks like that's a problem of server-side parser...
 

Written by Serge (serge@bestwebscripts.com)
CGI Scripts, Programming and Services
http://bestwebscripts.com
 

 
Report Bad Submission
Use this form to notify us if this entry should be deleted (i.e contains no code, is a virus, etc.).
Reason:
 
Your Vote!

What do you think of this article(in the Advanced category)?
(The article with your highest vote will win this month's coding contest!)
Excellent  Good  Average  Below Average  Poor See Voting Log
 
Other User Comments
6/1/2001 9:13:15 PM:Dave Overcash
Why not create a tutorial for a more used module, as mentioned above, sendmail. I believe this is installed on almost any server, and somewhat easier to use for begginer to advanced
Keep the Planet clean! If this comment was disrespectful, please report it:
Reason:

 
10/21/2001 7:37:07 PM:Ali
Hi, There are a lot of javascripts out there. 1. But I cannot find one that will enable my visitors to come to my site and send me a message from my form-mail in html format and send me attachments. Are you aware of any javascripts? Thanks Ali Idris_a liuk@yahoo.co.uk
Keep the Planet clean! If this comment was disrespectful, please report it:
Reason:

 
10/21/2001 7:38:37 PM:Ali
Hi, There are a lot of cgi/javascripts out there. 1. But I cannot find one that will enable my visitors to come to my site and send me a message from my form-mail in html format and send me attachments. Are you aware of any javascripts? Can you help me out? If so, can you please email me. Thanks Ali Idris_aliuk@yaho o.co.uk
Keep the Planet clean! If this comment was disrespectful, please report it:
Reason:

 
10/21/2001 7:41:33 PM:Ali
There is a javascript which I can put on my site and when a visitor visits my webpage (that has the javascript embedded) his/her desktop email client will email me an alert message that a visitor is visiting a certain link on my site. The alert message also informs me of my visitors computer details that a normal tracker would capture. You might check this script out: http://javascript.internet.com/u ser-details/visitor-monitor.html What I want is that, I want the alert message to not only inform me what link on my site a visitor is browsing but actually email me the whole html page on the alert message or atleast send me the html page in an attachment. So, I can actually see what page the visitor is browsing without clicking on the link and going to the page. Can you help me out? If so, can you please email me. Thanks Ali Idris_aliuk@yaho o.co.uk
Keep the Planet clean! If this comment was disrespectful, please report it:
Reason:

 
Add Your Feedback!
Note:Not only will your feedback be posted, but an email will be sent to the code's author in your name.

NOTICE: The author of this article has been kind enough to share it with you.  If you have a criticism, please state it politely or it will be deleted.

For feedback not related to this particular article, please click here.
 
Name:
Comment:

 

Categories | Articles and Tutorials | Advanced Search | Recommended Reading | Upload | Newest Code | Code of the Month | Code of the Day | All Time Hall of Fame | Coding Contest | Search for a job | Post a Job | Ask a Pro Discussion Forum | Live Chat | Feedback | Customize | Perl Home | Site Home | Other Sites | About the Site | Feedback | Link to the Site | Awards | Advertising | Privacy

Copyright© 1997 by Exhedra Solutions, Inc. All Rights Reserved.  By using this site you agree to its Terms and Conditions.  Planet Source Code (tm) and the phrase "Dream It. Code It" (tm) are trademarks of Exhedra Solutions, Inc.