Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How do I send emails via TLS authentication / encryption

Sending email

How do I send emails via TLS authentication / encryption

by  1DMF  Posted    (Edited  )
* 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

Code:
SEND_TYPE => '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
Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top