Sending a mail attachment using NET::SMTP is pretty easy, the only really hard bit is making sure the module is installed on your server and that of course you can run Perl. I’ve written this primarily from doing this from a server but you could ust as easily use this on websites etc…
Basically to send an attachment we need to read the file into a string/ array in Perl which in turn MIME will then associate the content of this string to a reserved file to be attached. We also use MIME to send mutipart emails, so we’ll be using boundaries to separate each part, the headers, the message and the attachment. The code is below:
#!/usr/bin/perl use Net::SMTP; use strict; use warnings; my $from = 'you@yourserver.co.uk'; my $to = 'me@luckylarry.co.uk'; my $to2 = 'someoneelse@luckylarry.co.uk'; my $attachFile = 'myFile.csv'; my $boundary = 'frontier'; my $data_file="/path/to/file/myFile.csv"; open(DATA, $data_file) || die("Could not open the file"); my @csv = DATA; close(DATA); my $smtp = Net::SMTP->new('smtp-out.yourserver.co.uk'); $smtp->mail($from); $smtp->recipient($to,$to2, { SkipBad => 1 }); $smtp->data(); $smtp->datasend("Subject: Test mail from you\n"); $smtp->datasend("MIME-Version: 1.0\n"); $smtp->datasend("Content-type: multipart/mixed;\n\tboundary=\"$boundary\"\n"); $smtp->datasend("\n"); $smtp->datasend("--$boundary\n"); $smtp->datasend("Content-type: text/plain\n"); $smtp->datasend("Content-Disposition: quoted-printable\n"); $smtp->datasend("\nTest From You\n"); $smtp->datasend("--$boundary\n"); $smtp->datasend("Content-Type: application/text; name=\"$attachFile\"\n"); $smtp->datasend("Content-Disposition: attachment; filename=\"$attachFile\"\n"); $smtp->datasend("\n"); $smtp->datasend("@csv\n"); $smtp->datasend("--$boundary--\n"); $smtp->dataend(); $smtp->quit; exit;
So first up we tell our perl script the installation of where Perl should be with the shebang – #!/usr/bin/perl. Next we say we’re going to use strict and warnings which is just good sense when using Perl, it means the program will error if you haven’t referenced your variables properly or got a typo somewhere.
We then define our variables, who the mail is coming from the recipients – this can be an array instead of a variable per user. Next we the file that we want to attach and the MIME boundary, so every time the boundary variable is called this will be the separator between content types. After this we declare where the actual data file is which we’re going to then line read the csv file and write that to an array to store each line – probably not the most efficient way for larger files.
We finally declare the SMTP object which points to your mail server. We follow this with defining the data for the SMTP object.
$smtp->mail($from); $smtp->recipient($to,$to2, { SkipBad => 1 });
Who is it coming from? Who is it going to? Skip any bad email addresses. You could use $smtp->to(); instead of recipients but I’m not sure that allows multiple mail addresses.
$smtp->data(); $smtp->datasend("Subject: Test mail from you\n"); $smtp->datasend("MIME-Version: 1.0\n"); $smtp->datasend("Content-type: multipart/mixed;\n\tboundary=\"$boundary\"\n"); $smtp->datasend("\n");
Start the building of the data. First the mail subject, the MIME type and the content type – we’re stating that there will be multiple mixed content sections and each section will be split as defined by the boundary section.
$smtp->datasend("--$boundary\n"); $smtp->datasend("Content-type: text/plain\n"); $smtp->datasend("Content-Disposition: quoted-printable\n"); $smtp->datasend("\nTest From You\n"); $smtp->datasend("--$boundary\n");
We separate that section with a boundary and then give the content type and disposition for our message in the email. Finishing with another boundary definition.
$smtp->datasend("Content-Type: application/text; name=\"$attachFile\"\n"); $smtp->datasend("Content-Disposition: attachment; filename=\"$attachFile\"\n"); $smtp->datasend("\n"); $smtp->datasend("@csv\n"); $smtp->datasend("--$boundary--\n");
We then do the same but this time for the mail attachment giving a content type and disposition. In this section we then read back the contents of our csv file that we read into an array at the start, this content gets then associated to the reserved filename in our mail attachment content type. Finish this with another boundary.
$smtp->dataend(); $smtp->quit; exit;
The final thing is to end the data stream/ definition for our NET::SMTP object , quit the SMTP object and then finally issue the exit command to exit our Perl script.
In this case I’m going to be calling my perl script from my bash script on the server, hence why I’m using exit as I really don’t want to keep this open!. And that’s it.
Perl documentation on NET::SMTP is here
More information for the MIME type for Email can be found here
This content is published under the Attribution-Noncommercial-Share Alike 3.0 Unported license.










Thanks, it helped to attach log files to my automated emails
You made it simple to understand and use !
http://www.ics.uci.edu/~rnahar
Thanks Rohit, glad it helped.
Larry,
With lotus notes everything seems to be working but my message shows up as 4Kbyte empty space.
My code follows
$Smtp->datasend( “To: “.’mel.pama@necam.com’.”\n” );
$Smtp->datasend( “From: “.’mel.pama@am.necel.com’.”\n” );
$Smtp->datasend( “Subject: renewalReport_test\n” );
$Smtp->datasend( “Mine-type: version 2.0\n”);
$Smtp->datasend( “Content-type: multipart/mixed;\n\tboundary=\”$boundary\”\n” );
$Smtp->datasend( “\n” );
$Smtp->datasend( “–$boundary\n” );
$Smtp->datasend( “Content-type: text/xhtml;”);
$Smtp->datasend( “Content-Disposition: quoted-printable\n”);
$Smtp->datasend( “$message\n” );
$Smtp->datasend(“\n”);
$Smtp->datasend( “–$boundary\n” );
$Smtp->datasend( “Content-type: text/xhtml;”);
$Smtp->datasend( “Content-Disposition: quoted-printable\n”);
$Smtp->datasend( “$message\n” );
$Smtp->datasend(“\n”);
$Smtp->datasend( “–$boundary–\n” );
$Smtp->datasend( “\n” );
$Smtp->quit();
Do you have any ideas about what might be wrong.
Thanks,
Mel Pama
Hey Mel,
If you look in your code you’ve got the MIME-type declared as ‘Mine-type’ other than that check your mail server can handle what you’re doing – I can’t see any reason why it wouldn’t.
Larry,
Thanks for the post, It worked perfectly fine for us. Just got another quick question? How can use this code to send multiple attachment.
Thanks,
Raj
Hi Raj,
In a simple way you can duplicate the boundary part with attachments – Or create a loop to go through all attachments and create the mail – depends on how many you have of course. I did find that it was a bit buggy to get this working – I’ll post my code up tomorrow (I have a decent working version of this at work)
Thanks Larry!! I really appreciate your help.
Hi Raj,
This should help you out, although for more than 3 attachments I’d look at doing a loop similar to what I do with the email addresses, e.g. just loop at this part:
$smtp->datasend(“Content-Type: application/text; name=\”$attachFile1\”\n”);
$smtp->datasend(“Content-Disposition: attachment; filename=\”$attachFile1\”\n”);
$smtp->datasend(“\n”);
$smtp->datasend(“@ronCsv\n”);
$smtp->datasend(“–$boundary\n”);
Anyway full code below, but without the loop. Hope that helps – if you get stuck then I guess I can write the loop.
Thanks Larry!! It worked out perfect for us.
cool
Always glad when people can use what I’ve found out or find the same issues.
Hi Larry,
I am new to perl coding, I get this error
“Can’t call method “mail” on an undefined value at line 18″
Could you please help
Thanks
Hi Kumar,
Make sure you’ve got NET::SMTP module installed for your Perl setup – Mail is a function of this module.
Not sure what system your using (unix etc..) but if you look online for some instructions for installing NET::SMTP that should help you out.