* Scroll to bottom if you just want to get your hands on the module ;-)
-----------------------------------------------------------------------
Ok, so you probably use MIME::Lite to send emails, especially if you have attachments, but what about sending via TLS authentication / encryption?
In today's modern world of hacking and packet sniffing, sending your email as securley as possible should be the standard not a luxury!
To help make sending emails from your perl applications simple and secure utilising Transport Layer Security (TLS) I have developed the SendMail.pm module.
Its use is really simple, you can send to multiple recipients and have multiple attachments and the module will also fall back to using standard SMTP if TLS fails to send.
---IMPORTANT NOTICE---
This module has dependencies on the following modules being installed on the web server...
MIME::Lite
Net::SMTP::TLS
Net::SSLeay
IO::Socket::INET
-------------------------------------------------------------------------
Not all attributes need to be passed to the sendmail constructor and there are some default attributes, which if omitted will be set as follows...
SEND_TYPE => 'TLS'
SERVER => '127.0.0.1'
PORT => 25
TIMEOUT => 30
If you need to provide user credentials for TLS there are the following optional attributes...
UID
PWD
The following attributes must be provided...
TO
FROM
SUBJECT
BODY
The following attributes are optional (though if you provide an attachment the corresponding NAME & TYPE attributes must be set...
FILE
FILE_NAME
FILE_TYPE
===================================================================
Ok, that's the brief overview out the way, here is a basic example of how to use it...
Code:
################
# Use SendMail #
################
use SendMail;
# create mailer object
my $mail = SendMail->new(
# remember to pass arrays as a reference to the array with a backslash \@myarray
SEND_TYPE => 'TLS',
SERVER => 'my.mailserver.com',
PORT => 25,
TIMEOUT => 30,
UID => 'myUserID',
PWD => 'myPassword',
TO => \@recip,
FROM => 'webmaster@mydomain.com',
SUBJECT => 'This is a test email subject!',
BODY => $body,
FILE => \@attach_file,
FILE_NAME => \@attach_name,
FILE_TYPE => \@attach_type
);
# send the mail
$mail->sendmail;
If you do not want to attempt to send the email via TLS, you can simply set the SEND_TYPE as SMTP
There are two built in arrays (ERRORS & WARNINGS) which are populated by the module so you can interogate them should you wish to.
Serious errors that fail to meet the sendmail 'preconditions' will stop any recipients receiving the email and the script will exit.
However, individual send errors or TLS warnings do not stop the flow of emails being sent and simply trap the errors as they occur and continues with the next recipient.
NOTE: Although recipients are passed as an array to the mailer script they are NOT sent as a single ('To:'), instead each recipient is sent the email individually, one at a time!
Here is the sendmail 'conditions' header
###################
# sendmail method #
###################
# Preconditions : requires valid values for :- recipient array (TO), subject scaler (SUBJECT), sender scalar (FROM) & email content scalar (BODY)
# : if attachment array (FILE) is provided, matching arrays for (FILE_NAME & FILE_TYPE) must be provided.
#
# Postconditions : an attempt to send email via TLS using login credentials (UID & PWD) if provided, on port (PORT) is made or by standard SMTP,
# : selectable via scaler (SEND_TYPE) to mail server (SERVER).
###################
* Note on attachments...
FILE :- Needs to be the full path and file name of the attachment.
FILE_NAME :- You can give the attachment a different filename from the actual file name if you so desire, but it must be supplied.
FILE_TYPE :- These need to be the MIME type of the attachments, you can view a full list of MIME types via http://en.wikipedia.org/wiki/Internet_media_type
You can download the SendMail.pm module with the link below or copy/paste the code shown into notepad and save it as SendMail.pm
http://dance-music.org/mime-lite-tls-email-encryption.html
Included in the zip file is an example mailer script showing basic usage.
If you have any queries, want to report any bugs or give suggestions, feel free to drop me an email.
Enjoy the module and happy emailing via TLS encryption!
-------------------------------------------------------
SendMail.pm
Code:
#############################################################################################################################
# Name : SendMail.pm
# Version : v0.02
# Author : Craig Chant (DJ - C.D.C.) - http://dance-music.org - dmo@dance-music.org
# Copyright : Craig Chant (c) 29/06/2011
# Acknowledgement : Tatsuhiko Miyagawa - http://plagger.org/trac/browser/trunk/plagger/lib/Plagger/Plugin/Publish/Gmail.pm
# Special thanks to : Dr. ishnid - http://ishnid.ucd.ie/ - A gentleman and a scholar!
##############################################################################################################################
# OO Perl module to send email securely over TLS encryption / authentication or normal SMTP. Requires following Perl modules
# to be installed on server...
#
# MIME::Lite
# Net::SMTP::TLS
# Net::SSLeay
# IO::Socket::INET
#
###############################################################################################################################
######################
# Set Error Trapping #
######################
use CGI::Carp qw/fatalsToBrowser warningsToBrowser/;
use warnings;
use strict;
##########################
# Set Package Name Space #
##########################
package SendMail;
########################
# Public Class Version #
########################
our $VERSION = '0.02';
###########################
# Class Constructor New() #
###########################
sub new {
# class variable
my $class = shift;
# class oject
my $self;
# class attributes
$self = {
@_,
ERRORS => [],
WARNINGS => []
};
# Default attribute values
# Server
if(! $self->{SERVER}){
$self->{SERVER} = '127.0.0.1';
}
# Send type
if(! $self->{SEND_TYPE}){
$self->{SEND_TYPE} = 'TLS';
}
# Port
if(! $self->{PORT}){
$self->{PORT} = 25;
}
# Timeout
if(! $self->{TIMEOUT}){
$self->{TIMEOUT} = 30;
}
# Bless the data structure, making it a true object
bless ($self,$class);
# Return instantiated object
return $self;
}
###################################################
################## CLASS METHODS ##################
###################################################
###################
# sendmail method #
###################
# Preconditions : requires valid values for :- recipient array (TO), subject scaler (SUBJECT), sender scalar (FROM) & email content scalar (BODY)
# : if attachment array (FILE) is provided, matching arrays for (FILE_NAME & FILE_TYPE) must be provided.
#
# Postconditions : an attempt to send email via TLS using login credentials (UID & PWD) if provided, on port (PORT) is made or by standard SMTP,
# : selectable via scaler (SEND_TYPE) to mail server (SERVER).
###################
sub sendmail {
# Assign object
my $self = shift;
# Check for valid email details
# Recipients' email
if (! $self->{TO}){
$self->error('Missing recipients email address');
}
# Subject
if (! $self->{SUBJECT}){
$self->error('Missing email subject');
}
# Sender email
if (! $self->{FROM}){
$self->error('Missing sender email address');
}
# Email content body HTML
if (! $self->{BODY}){
$self->error('Missing email body content');
}
# Check for attachment
if (defined @{$self->{FILE}}){
for (my $i=0; $i<@{$self->{FILE}}; $i++){
if(! -e $self->{FILE}[$i]){
$self->error("Missing attachment file : $self->{FILE}[$i]");
}
if(! $self->{FILE_NAME}[$i]){
$self->error("Missing attachment file name : ( $self->{FILE}[$i] )");
}
if(! $self->{FILE_TYPE}[$i]){
$self->error("Missing attachment file type : ( $self->{FILE}[$i] )");
}
}
}
# if no errors
if (! @{$self->{ERRORS}}){
# Send email
$self->sendit;
# check send errors
return ! @{$self->{ERRORS}} ? 1 : 0;
}
else{return 0;}
}
########################
# sendit helper method #
########################
sub sendit {
# Assign object
my $self = shift;
##################
# Use MIME::Lite #
##################
use MIME::Lite;
# Add MIME::Lite TLS hack
&mimehack;
# Loop recipients and send
foreach my $to (@{$self->{TO}}){
# create new msg object
my $msg = MIME::Lite->new(
From => $self->{FROM},
To => $to,
Subject => $self->{SUBJECT},
Type => 'multipart/mixed'
);
# check for attachments
if (defined @{$self->{FILE}}){
for (my $i=0; $i<@{$self->{FILE}}; $i++){
$msg->attach(
Type => $self->{FILE_TYPE}[$i],
Path => $self->{FILE}[$i],
Filename => $self->{FILE_NAME}[$i]
);
}
}
# add email
$msg->attach(
Type => 'TEXT/HTML',
Data => $self->{BODY}
);
# check send type
if ($self->{SEND_TYPE} eq 'TLS'){
# TLS arguments
my @tls_args = (
$self->{SERVER},
Port => $self->{PORT},
Timeout => $self->{TIMEOUT}
);
# check for user id
if (defined $self->{UID}){
push (@tls_args,User => $self->{UID});
}
# check for password
if (defined $self->{PWD}){
push (@tls_args,Password => $self->{PWD});
}
# send via TLS or SMTP if TLS fails
if (! $msg->send_by_smtp_tls($self, @tls_args)){
eval {$msg->send('smtp', $self->{SERVER}, Timeout => $self->{TIMEOUT})};
$self->error($@) if $@;
}
}
else{
# send via SMTP
eval {$msg->send('smtp', $self->{SERVER}, Timeout => $self->{TIMEOUT})};
$self->error($@) if $@;
}
}
}
#######################
# MIME::Lite TLS Hack #
#######################
sub mimehack {
# Add MIME::Lite hack to support TLS authentication / encryption
*MIME::Lite::send_by_smtp_tls = sub {
# Set objects & arguments
my($self, $sendmail, @args) = @_;
# Create SMTP TLS client:
eval{
# Use Net::SMTP::TLS
require Net::SMTP::TLS;
my $smtp = MIME::Lite::SMTP::TLS->new(@args);
$smtp->mail($self->get('From'));
$smtp->to($self->get('To'));
$smtp->data();
# MIME::Lite can print() to anything with a print() method:
$self->print_for_smtp($smtp);
$smtp->dataend();
};
# check for TLS errors and set warnings
$sendmail->warning($@) if $@;
return $@ ? 0 : 1;
};
@MIME::Lite::SMTP::TLS::ISA = qw( Net::SMTP::TLS );
sub MIME::Lite::SMTP::TLS::print { shift->datasend(@_) }
}
########################
# errors helper method #
########################
sub error {
# get object
my $self = shift;
# add error
push @{$self->{ERRORS}}, @_;
}
##########################
# warnings helper method #
##########################
sub warning {
# get object
my $self = shift;
# add warning
push @{$self->{WARNINGS}}, @_;
}
#############################################
######### End of Module - Return 1; #########
#############################################
1;
##############################
# Bug Fix v0.02 - 08/08/2011 #
#################################################################
# Fixed defined error if attachments attribute was not provided