Email::MIME::Creator
Thursday, December 9, 2004, 11:17 PM
How to Use Email::MIME::Creator

While attempting to automatically generate a somewhat complex multipart email in Perl, I came to the realization that the Email::MIME group of Perl modules is very nice and very powerful, but it's really poorly documented. It's not all that hard to use, but it's nearly impossible to figure out, especially if you don't have much experience with formatting multipart MIME emails.

So, I'm going to show how to generate a couple of different email types using Email::MIME::Creator in the hopes that someone else can benefit from the toils of my labor in figuring out how exactly this wonderful Perl module works.

Generating a multipart ASCII-text / HTML email

First and formost, the modules must included at the beginning of the script:

use Email::MIME;
use Email::MIME::Creator;
use Email::Send qw:SMTP:;

Then, we can format both parts of our message:

$ascii_message="Hi! This is the text of my ASCII email.";
$html_message="<html><body>Hi! This is the text of my HTML email."</body></html>";

And pick who we're planning on sending our email from and to:

$mailFrom="me@nowhere.com";
$mailTo="you@nowhere.com";

Then, we have to define both parts of our multipart email. Note that the content_type is set to text/plain or text/html respectively, and the body is set to our $ascii_message, or $html_message, which we set just a moment ago:

my @parts = (
# make the text part first
Email::MIME->create(
attributes => {
content_type => "text/plain",
format => "flowed",
charset => "US-ASCII",
},
body => $ascii_message,
),
Email::MIME->create(
attributes => {
content_type => "text/html",
charset => "US-ASCII",
encoding => "quoted-printable",
format => "flowed",
},
body => $html_message,
),
);

Then we have to create the email from the parts defined above:

my $email = Email::MIME->create(
header => [ From => $mailFrom ],
parts => [ @parts ],
);

And set some standard headers:

$email->header_set( 'X-PoweredBy' => 'Gersic.com Email System' );
$email->header_set( To => $mailTo );
$email->header_set( Subject => 'This email is very very important' );
$email->header_set( Cc => 'someone@cc.com' );
$email->header_set( Bcc => 'someone@bcc.com' );


And here's the most important thing to note, for making sure this message gets formatted the way you'd expect it to (i.e. so that an HTML-enabled email client will show the HTML version, and a text-only email client will show the ASCII version). You have to change the content type of the email to multipart/alternative instead of multipart/mixed, and you also have to set the MIME boundary of the email, so that it won't be randomly generated:

$email->header_set( 'Content-Type' => 'multipart/alternative' );
$email->boundary_set('GERSIC_Boundary_text');

Then, you have to send the email...very important:

Email::Send::SMTP::send( $email, $mailserver );


Generating an email with an attachment

Generating a text-based email with an attachment is basically the same as generating a multipart ascii/html email. Only, this time instead of setting the content_type to multipart/alternative, we'll leave it as the default multipart/mixed. First, we'll open the file:

$file_path="heresafile.pdf";
open(PDF, $file_path);
my $pdf = join('', <PDF>);
close PDF;

And then we'll create both of the parts for the email:

my @parts= (
# make the text part first
Email::MIME->create(
attributes => {
content_type => "text/plain",
format => "flowed",
charset => "US-ASCII",
},
body => $ascii_message,
),
# put the file attachment second
Email::MIME->create(
attributes => {
filename => $file_path,
content_type => "application/pdf",
encoding => "base64",
name => $file_path,
},
body => $pdf,
),
);

That's it. Just format everything like you did above, only leave out the bit about setting the content_type to multipart/alternative, and setting the boundary, and you can go ahead and send the email.

Generating a multipart ASCII / HTML email with an attachment

In order to generate a multipart email with both an ASCII part and an HTML part, and an attachment, we'll need to nest a multipart/alternative section within the multipart/mixed section. This is actually fairly easy to do.

First, we set up the ASCII and HTML portions of the message just like we did before:

my @parts = (
# make the text part first
Email::MIME->create(
attributes => {
content_type => "text/plain",
charset => "US-ASCII",
encoding => "quoted-printable",
format => "flowed",
},
body => $ascii_message,
),
# make the html version second
Email::MIME->create(
attributes => {
content_type => "text/html",
charset => "US-ASCII",
encoding => "quoted-printable",
format => "flowed",
},
body => $html_message,
),
);

And then we'll create the inner portion of the email, which will be nested later:

my $inner = Email::MIME->create(
parts => [ @parts ],
);

Then we need to set the content_type on this inner section to multipart/alternative:

$inner->header_set( 'Content-Type' => 'multipart/alternative' );
$inner->boundary_set('GERSIC_Boundary_text');

After that, we can create the outer portion of our email, which will include the $inner portion as the first part, and attach the file as the second part:

open(PDF, $pdf_path);
my $pdf = join('', <PDF>);
close PDF;

my @wrapper = (
# make the text part first
$inner,
# put the file attachment second
Email::MIME->create(
attributes => {
filename => $file_path,
content_type => "application/pdf",
encoding => "base64",
name => $file_path,
},
body => $pdf,
),
);

Lastly, we create our email as before, and it's ready to send:

my $email = Email::MIME->create(
header => [ From => 'osdb@teleologic.net' ],
parts => [ @wrapper ],
);

$email->header_set( 'X-PoweredBy' => 'Gersic.com Email System' );
$email->header_set( To => $mailTo );
$email->header_set( Subject => 'This email is very very important' );
$email->header_set( Cc => 'someone@cc.com' );
$email->header_set( Bcc => 'someone@bcc.com' );