Category: Email
Author/Contact Info J. Gregory <john@johngregory.me.uk>
Description:

A nice simple (yet decently powerful) object orientated interface to Net::SMTP.

Features included:

  • Plain text / Html / Mixed content types
  • Multiple Recipients (to/cc/bcc)
  • Single and multipart emails (html with text alternative)
  • Support for embedded and HREF referenced images in Html context
  • Easy attachments

The email message encodings are based on the standard email RFCs and the output of the Eudora mail client.

N.B. This code has been used in production environments but I don't recommend such usage without thorough testing.

This module is provided without warranty although I will be happy to try to answer any queries you may have (if I can :-))

The most upto date version can be downloaded (along with it's HTML pod docs) from this location.

package JMailer;
require 5.6.0;
use strict;

our $VERSION = '2.0';
our $AUTHOR = 'J. Gregory <john@johngregory.me.uk>';

use Net::SMTP;
use MIME::Base64;

# ====================================================================
+====
# JMailer
#
# ====================================================================
+====

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self = {};
        bless $self, $class;

        $self->{'TO'} = {};
        $self->{'FROM'} = {};
        $self->{'CC'} = {};
        $self->{'BCC'} = {};
        $self->{'MESSAGE'} = '';
        $self->{'TEXT_PLAIN'} = '';
        $self->{'TEXT_HTML'} = '';
        $self->{'ENCODED_ATTACHMENTS'} = [];
        $self->{'EMBEDDED_IMAGE_ENCODINGS'} = [];
        $self->{'MAILSERVER_IP'};
        $self->{'DEBUG'}        =       0;      # 0 = off, 1 = on

        # If we're in ASP, we need to remap our cwd so that it doesn't
+ try to offload
        # us to WINNT/System32 or something....
        if ( $main::Server ) {
                # Find out where we're running...
                my $here = $main::Server->MapPath($main::Request->Serv
+erVariables('PATH_INFO'));
                # Strip the script name....
                $here =~ s/(.*\\).*/$1/g;
                # chdir so we're pointing at the right "base" for uplo
+ads
                chdir($here);
        }

        require Sys::Hostname;
            my $hostname = Sys::Hostname::hostname();
            $self->{'CLIENT'} = "$hostname";

    return $self;
}

# ====================================================================
+====
# s e n d M a i l ( )

sub sendMail {
    my $self = shift;
    $self->_buildMessage();
    my $ret = $self->_smtp();
    return $ret;
}

# ====================================================================
+====
# s u b j e c t
#
# Sets the subject line of the email - returns the set subject, or ori
+ginial subject if it failed / was
# supplied a blank parameter.

sub subject {
    my $self = shift;
    my $subj = shift;
    if ( $subj ) {
        $self->{'SUBJECT'} = "$subj";
    }
    return $self->{'SUBJECT'};
}

# ====================================================================
+====
# a t t a c h m e n t

sub attachment {
    my $self = shift;
        if (@_) {
                my $filename = shift;
                if ($self->_prepareAttachment(\$filename)) { return 1;
+ }
        }
        return 0;
}

# ====================================================================
+====
# f r o m ( )

sub from {
    my $self = shift;
    my $address = shift;
    my ($email, $alias) = $self->_parseAddress( $address );
    $self->{'FROM'} = {};
    $self->{'FROM'} = { "$email" => "$alias" };
    return;
}

# ====================================================================
+====
# t o ( )

sub to {
    my $self = shift;
    my @addr = @_;       # Should be a list of addresses
    $self->{'TO'}   =   {};    # Clear any existing addresses
    my @parsed;
        foreach my $ad ( @addr ) {
               @parsed = $self->_parseAddress( $ad );
               $self->{'TO'}->{$parsed[0]} = $parsed[1];
        }
    return;
}

# ====================================================================
+====
# c c ( )

sub cc {
    my $self = shift;
    my @addr = @_;       # Should be a list of addresses
    $self->{'CC'}   =   {};    # Clear any existing addresses
    my @parsed;
        foreach my $ad ( @addr ) {
               @parsed = $self->_parseAddress( $ad );
               $self->{'CC'}->{$parsed[0]} = $parsed[1];
        }
    return;
}

# ====================================================================
+====
# b c c ( )

sub bcc {
    my $self = shift;
    my @addr = @_;       # Should be a list of addresses
    $self->{'BCC'}   =   {};    # Clear any existing addresses
    my @parsed;
        foreach my $ad ( @addr ) {
               @parsed = $self->_parseAddress( $ad );
               $self->{'BCC'}->{$parsed[0]} = $parsed[1];
        }
    return;
}

# ====================================================================
+====
# s m t p S e r v e r ( )
#
# Set the IP of the SMTP server that we wish to use - returns the valu
+e set, or existing if
# no params supplied.

sub smtpServer {
    my $self = shift;
    my $ip = shift;
        if ( $ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ ) {
            $self->{'MAILSERVER_IP'} = "$ip";
        }
    return $self->{'MAILSERVER_IP'};
}

# ====================================================================
+====
# t e x t ( )

sub text {
    my $self = shift;
    my $text = shift;
        if ( $text ) {
            $self->{'TEXT_PLAIN'} = "$text";
        }
    return;
}

# ====================================================================
+====
# h t m l ( )

sub html {
    my $self = shift;
    my $html = shift;
        if ( $html ) {
            $self->{'TEXT_HTML'} = "$html";
        }
    return;
}

# ====================================================================
+====
# d e b u g ( )

sub debug() {
    my ($self, $debug) = @_;
    $self->{'DEBUG'} = (($debug) ? 1 : 0);
    return;
}

# ====================================================================
+====
# P R I V A T E
# ====================================================================
+====
# _ s m t p ( )

sub _smtp {

    my $self = shift;

    my $message = $self->{'MESSAGE'};
    my $client = $self->{'CLIENT'};
    my ($from) = keys(%{$self->{'FROM'}});

            my $smtp = Net::SMTP->new($self->{'MAILSERVER_IP'}, Timeou
+t => 40, Hello => "$client", Debug=>"$self->{'DEBUG'}");
            if ( ! $smtp ) { return 0; }    # No object created - retu
+rn false;

            $smtp->mail($from);
            foreach my $to ( keys ( %{$self->{'TO'}} ) ) { $smtp->to($
+to); }
            foreach my $cc ( keys ( %{$self->{'CC'}} ) ) { $smtp->cc($
+cc); }
            foreach my $bcc ( keys ( %{$self->{'BCC'}} ) ) { $smtp->bc
+c($bcc); }
            $smtp->data();
            $smtp->datasend($message);
            $smtp->dataend();

        $smtp->quit();
        return 1;
}

# ====================================================================
+====
# _ b u i l d M e s s a g e ( )

sub _buildMessage {
    my $self = shift;

        my ($fromkey) = keys (%{$self->{'FROM'}});
        my $from = $self->{'FROM'}->{$fromkey};
        my $subject = $self->{'SUBJECT'};
        my $text_html = $self->{'TEXT_HTML'};       # This is optional
+ and allowed to be empty (not checked by &_check_data() )
        my $text_plain = $self->{'TEXT_PLAIN'};
        my @attachments = @{$self->{'ENCODED_ATTACHMENTS'}};

        # Strip any preceeding and ending \n from the plain text
        $text_plain =~ s/^\n//;
        $text_plain =~ s/\n$//m;

        # Prepare any HTML
        if ( $text_html ) {
            $self->_prepareHtml();
            $text_html = $self->{'TEXT_HTML'};
        } # end if

        my @inline = @{$self->{'EMBEDDED_IMAGE_ENCODINGS'}};    # Have
+ to call this AFTER prepare HTML else there won't be any, even if the
+re are.

        # Common start to all messages
        my $message = '';
        $message .= "From: $from\n";
        $message .= "To: " . (join ", ", ( keys ( %{$self->{'TO'}} ) )
+ ) . "\n";
        $message .= "CC: " . (join ", ", ( keys ( %{$self->{'CC'}} ) )
+ ) . "\n" if ( $self->{'CC'});
        $message .= "BCC: " . (join ", ", ( keys ( %{$self->{'BCC'}} )
+ ) ) . "\n" if ( $self->{'BCC'});
        $message .= "Subject: $subject\n";
        $message .= "Date: " . $self->_getFormattedDate() . "\n";
        $message .= "X-Mailer: JMailer v$VERSION\n";
        $message .= "MIME-Version: 1.0\n";

        my $messageData = '';

        # Start with the plain text that all messages need to have
        $messageData = $self->_wrapPlainText();

        # If we have HTML we wrap the plain text block with an "altern
+ative" boundary
        if ( $text_html ) {
            $messageData = $self->_wrapHtml( \$messageData );
        }

        # If we have attachments XOR inline images we wrap one or the 
+other - doing both is different
        if ( @inline xor @attachments ) {
                if ( @inline ) {        # Use "related" type
                    $messageData = $self->_wrapInline( \$messageData )
+;
                } elsif ( @attachments ) {  # Use "Mixed" type
                    $messageData = $self->_wrapAttach( \$messageData )
+;
                }
        }

        if ( @inline and @attachments ) {
              $messageData = $self->_wrapInline( \$messageData );   # 
+Do both...
              $messageData = $self->_wrapAttach( \$messageData );
        }

        $message .= $messageData;

        # "Finish off" the last Message-Boundary if there is one.
        $message =~ s/(.*)(__Message-Boundary__) /$1$2--/xs;

        my $messageTemp = $message;
        open (MSG, ">message.txt");
            print MSG $messageTemp;
            $messageTemp =~ s/</&lt;/g;
            $messageTemp =~ s/\n/<br \/>/g;
            $messageTemp =~ s/\s/&nbsp;/g;
            $messageTemp =~ s/\[(\/?b)\]/<$1>/g;            
        close(MSG);

        $self->{'MESSAGE'} = $message;     # Store the completed messa
+ge
    return 1;    # Go back okay.
}

# ====================================================================
+====
# _ g e t F o r m a t t e d D a t e ( )

sub _getFormattedDate
{
    my $self = shift;
    my @days = ();
    my @months = ();
    my $bst = undef;
    my $date = undef;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localti
+me(time);
    @days = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
    @months = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','
+Oct','Nov','Dec');
    $year += 1900;
    if($isdst) { $bst = " +0100" }
    $date = "$days[$wday], $mday $months[$mon] $year $hour:$min:$sec$b
+st";
    return $date;
}

# ====================================================================
+====
# _ p r e p a r e H t m l ( )

sub _prepareHtml {
    my $self = shift;
        my @image_tags = ();        # Tags parsed out of the html text
        my @inline_images = ();     # Names of images marked as "inlin
+e" - will be imported into the eMail
        my $image_name = undef;
        my $count = 0;                  # Counter used when encoding t
+he <IMG> tag of inline images.
        my $html_text_ref = \$self->{'TEXT_HTML'};      # Use a ref so
+ that we edit the real text and not a copy.

        # Strip any preceeding and ending \n
        ${$html_text_ref} =~ s/^\n//;
        ${$html_text_ref} =~ s/\n$//m;

        # Get all the <IMG> tags from the text
        (@image_tags) = ( ${$html_text_ref} =~ /(<img.*?>)/igs );

        # Process these tags and extract the SRC attributes
        foreach my $image_tag (@image_tags) {
                ($image_name) = ( $image_tag =~ /src= (?:\'|\")? ( [ \
+w\d\.\/\: ]* ) (?:\'|\")? /ix );
                    if ( $image_name !~ /^http/ ) {                   
+             # Inline image if no "http"
                            push @inline_images , $image_name;
                    }
        }

        # If we found any inline images then we grab them and base64 e
+ncode them.
        if (@inline_images) {
            my $encodedImage;
            my $type;
                foreach my $inline_image (@inline_images) {
                        ${$html_text_ref} =~ s/$inline_image/cid\:img$
+count/g;          # Encode the image tags
                        $inline_image =~ s/[\"\']//g;

                        # ## Reverse the string, get the extension, an
+d put it back the right way ## #
                        my $rev_image_name = join "",(reverse(split //
+,$inline_image));
                            ($type) = ($rev_image_name =~ /  ^([^\.]+)
+ /x);
                            $type = join "",(reverse(split //,$type));

                            if (( $type eq 'jpg' )||( $type eq 'jpe' )
+) { $type = 'jpeg' }; # Clean a jpg extension

                            my $cleanName = $inline_image;
                                $cleanName =~ s/.*?\/([^\/]+)$/$1/;

                        $encodedImage = '';
                        # $encodedImage = "--__Middle-Boundary__\n";
                        $encodedImage .= "Content-Type: image/$type\; 
+ name=\"$cleanName\"\n";          # <----- !!!!!!
                        $encodedImage .= "Content-Transfer-Encoding: b
+ase64\n";
                        $encodedImage .= "Content-Disposition: inline;
+ filename=\"$cleanName\"\n";
                        $encodedImage .= "Content-ID: <img$count>";
                        $encodedImage .= "\n\n";
                        $encodedImage .= $self->_encode64(\$inline_ima
+ge);

                        push @{$self->{'EMBEDDED_IMAGE_ENCODINGS'}} , 
+$encodedImage;
                        $count++;
                } # end foreach
        } # end if

    return 1;
}

# ====================================================================
+====
# _ p r e p a r e A t t a c h m e n t ( )

sub _prepareAttachment {
    my $self = shift;
        my $fileref = shift;

        my $attachment = undef;
        my $base64encoded = '';
        my ($extension) = ($$fileref =~ /[^\.]\.(.+)/);
        # Strip any preceeding directories from the attachment name...
        my $cleanName = $$fileref;
            $cleanName =~ s/.*?\/([^\/]+)$/$1/;
        my $type = $self->_getMIME($extension);

            # If it's plaintext, we don't bother to base 64 it...
            if ( $extension eq 'txt' ) {
                    my $filedata = '';
                        open (IN, "<$$fileref");
                            while(<IN>) { $filedata .= $_; }
                        close(IN);
                    $attachment .= "Content-Type: text/plain; charset=
+\"us-ascii\"\n";
                    $attachment .= "Content-Disposition: attachment; f
+ilename=\"$cleanName\"";
                    $attachment .= "\n\n";
                    $attachment .= $filedata;
                    push @{$self->{'ENCODED_ATTACHMENTS'}}, $attachmen
+t;
                    return 1;
            } else {
                    if ($base64encoded = $self->_encode64($fileref)) {
                        $attachment .= "Content-Type: $type; name=\"$c
+leanName\"\n";
                        $attachment .= "Content-Transfer-Encoding: Bas
+e64\n";
                        $attachment .= "Content-Disposition: attachmen
+t; filename=\"$cleanName\"";
                        $attachment .= "\n\n";
                        $attachment .= $base64encoded;
                        push @{$self->{'ENCODED_ATTACHMENTS'}}, $attac
+hment;
                        return 1;
                    } else {
                        return 0;
                    }
            }
}

# ====================================================================
+====
# _ e n c o d e 6 4 ( )

sub _encode64 {
    my $self = shift;
        my $fileref = shift;
        open(FILE, "<$$fileref") or die "Cannot open file for encoding
+: $$fileref: $!\n\n";
        binmode(FILE);
            my $buf;
            my $encoded_file = '';
                        while(read(FILE, $buf, 57)) {
                            $encoded_file .= encode_base64($buf);
                        }
        close(FILE);
        return $encoded_file;
}

# ====================================================================
+====
# _ w r a p P l a i n T e xt ( )

sub _wrapPlainText {
    my $self = shift;
    my $msgblock = << "EOB"
Content-Type: text/plain; charset="us-ascii"; format=flowed

$self->{'TEXT_PLAIN'}
EOB
;
    return $msgblock;
}

# ====================================================================
+====
# _ w r a p H t m l ( )

sub _wrapHtml {
    my $self = shift;
    my $textref = shift;
    my @inline= $self->{'EMBEDDED_IMAGE_ENCODINGS'};
    my $msgblock = << "EOB"
Content-type: multipart/alternative;
    boundary="================941224239==.ALT"

--================941224239==.ALT
$$textref

--================941224239==.ALT
Content-Type: text/html; charset="iso-8859-1"

$self->{'TEXT_HTML'}

--================941224239==.ALT--
EOB
;

    return $msgblock;
}

# ====================================================================
+====
# _ w r a p I n l i n e ( )

sub _wrapInline {
    my $self = shift;
    my $msgtextref = shift;
    my $msgblock = << "EOB"
Content-type: multipart/related;
    type="multipart/alternative";
    boundary="================941224239==.REL"

--================941224239==.REL
$$msgtextref

EOB
;
foreach my $il (@{$self->{'EMBEDDED_IMAGE_ENCODINGS'}}) {
$msgblock .= << "EOB"
--================941224239==.REL
$il
EOB
;
} # end foreach
    $msgblock .= "\n--================941224239==.REL--";   # Finish o
+ff the boundary
    return $msgblock;
}

# ====================================================================
+====
# _ w r a p A t t a c h ( )

sub _wrapAttach {
    my $self = shift;
    my $msgtextref = shift;
    my $msgblock = << "EOB"
Content-type: multipart/mixed; boundary="================941224239==.M
+IX";

--================941224239==.MIX
$$msgtextref

EOB
;
foreach my $en (@{$self->{'ENCODED_ATTACHMENTS'}}) {  # ATTACHMENTS
$msgblock .= << "EOB"
--================941224239==.MIX
$en
EOB
;
} # end foreach
    $msgblock .= "--================941224239==.MIX--";

    return $msgblock;
}

# ====================================================================
+====
# _ g e t M I M E ( )

sub _getMIME {
    my $self = shift;
    my $extension = shift;

    my %mimeTypes = ();
        $mimeTypes{'.3dm'} = "x-world/x-3dmf";
        $mimeTypes{'.3dmf'} = "x-world/x-3dmf";
        $mimeTypes{'.a'} = "application/octet-stream";
        $mimeTypes{'.aab'} = "application/x-authorware-bin";
        $mimeTypes{'.aam'} = "application/x-authorware-map";
        $mimeTypes{'.aas'} = "application/x-authorware-seg";
        $mimeTypes{'.abc'} = "text/vnd.abc";
        $mimeTypes{'.acgi'} = "text/html";
        $mimeTypes{'.afl'} = "video/animaflex";
        $mimeTypes{'.ai'} = "application/postscript";
        $mimeTypes{'.aif'} = "audio/x-aiff";
        $mimeTypes{'.aifc'} = "audio/x-aiff";
        $mimeTypes{'.aiff'} = "audio/x-aiff";
        $mimeTypes{'.aim'} = "application/x-aim";
        $mimeTypes{'.aip'} = "text/x-audiosoft-intra";
        $mimeTypes{'.ani'} = "application/x-navi-animation";
        $mimeTypes{'.aos'} = "application/x-nokia-9000-communicator-ad
+d-on-software";
        $mimeTypes{'.aps'} = "application/mime";
        $mimeTypes{'.arc'} = "application/octet-stream";
        $mimeTypes{'.arj'} = "application/octet-stream";
        $mimeTypes{'.art'} = "image/x-jg";
        $mimeTypes{'.asf'} = "video/x-ms-asf";
        $mimeTypes{'.asm'} = "text/x-asm";
        $mimeTypes{'.asp'} = "text/asp";
        $mimeTypes{'.asx'} = "video/x-ms-asf-plugin";
        $mimeTypes{'.au'} = "audio/x-au";
        $mimeTypes{'.avi'} = "video/x-msvideo";
        $mimeTypes{'.avs'} = "video/avs-video";
        $mimeTypes{'.bcpio'} = "application/x-bcpio";
        $mimeTypes{'.bin'} = "application/x-macbinary";
        $mimeTypes{'.bm'} = "image/bmp";
        $mimeTypes{'.bmp'} = "image/x-windows-bmp";
        $mimeTypes{'.boo'} = "application/book";
        $mimeTypes{'.book'} = "application/book";
        $mimeTypes{'.boz'} = "application/x-bzip2";
        $mimeTypes{'.bsh'} = "application/x-bsh";
        $mimeTypes{'.bz'} = "application/x-bzip";
        $mimeTypes{'.bz2'} = "application/x-bzip2";
        $mimeTypes{'.c'} = "text/x-c";
        $mimeTypes{'.c++'} = "text/plain";
        $mimeTypes{'.cat'} = "application/vnd.ms-pki.seccat";
        $mimeTypes{'.cc'} = "text/x-c";
        $mimeTypes{'.ccad'} = "application/clariscad";
        $mimeTypes{'.cco'} = "application/x-cocoa";
        $mimeTypes{'.cdf'} = "application/x-netcdf";
        $mimeTypes{'.cer'} = "application/x-x509-ca-cert";
        $mimeTypes{'.cha'} = "application/x-chat";
        $mimeTypes{'.chat'} = "application/x-chat";
        $mimeTypes{'.class'} = "application/x-java-class";
        $mimeTypes{'.com'} = "text/plain";
        $mimeTypes{'.conf'} = "text/plain";
        $mimeTypes{'.cpio'} = "application/x-cpio";
        $mimeTypes{'.cpp'} = "text/x-c";
        $mimeTypes{'.cpt'} = "application/x-cpt";
        $mimeTypes{'.crl'} = "application/pkix-crl";
        $mimeTypes{'.crt'} = "application/x-x509-user-cert";
        $mimeTypes{'.csh'} = "text/x-script.csh";
        $mimeTypes{'.css'} = "text/css";
        $mimeTypes{'.cxx'} = "text/plain";
        $mimeTypes{'.dcr'} = "application/x-director";
        $mimeTypes{'.deepv'} = "application/x-deepv";
        $mimeTypes{'.def'} = "text/plain";
        $mimeTypes{'.der'} = "application/x-x509-ca-cert";
        $mimeTypes{'.dif'} = "video/x-dv";
        $mimeTypes{'.dir'} = "application/x-director";
        $mimeTypes{'.dl'} = "video/x-dl";
        $mimeTypes{'.doc'} = "application/msword";
        $mimeTypes{'.dot'} = "application/msword";
        $mimeTypes{'.dp'} = "application/commonground";
        $mimeTypes{'.drw'} = "application/drafting";
        $mimeTypes{'.dump'} = "application/octet-stream";
        $mimeTypes{'.dv'} = "video/x-dv";
        $mimeTypes{'.dvi'} = "application/x-dvi";
        $mimeTypes{'.dwf'} = "model/vnd.dwf";
        $mimeTypes{'.dwg'} = "image/x-dwg";
        $mimeTypes{'.dxf'} = "image/x-dwg";
        $mimeTypes{'.dxr'} = "application/x-director";
        $mimeTypes{'.el'} = "text/x-script.elisp";
        $mimeTypes{'.elc'} = "application/x-elc";
        $mimeTypes{'.env'} = "application/x-envoy";
        $mimeTypes{'.eps'} = "application/postscript";
        $mimeTypes{'.es'} = "application/x-esrehber";
        $mimeTypes{'.etx'} = "text/x-setext";
        $mimeTypes{'.evy'} = "application/x-envoy";
        $mimeTypes{'.exe'} = "application/octet-stream";
        $mimeTypes{'.f'} = "text/x-fortran";
        $mimeTypes{'.f77'} = "text/x-fortran";
        $mimeTypes{'.f90'} = "text/x-fortran";
        $mimeTypes{'.fdf'} = "application/vnd.fdf";
        $mimeTypes{'.fif'} = "image/fif";
        $mimeTypes{'.fli'} = "video/x-fli";
        $mimeTypes{'.flo'} = "image/florian";
        $mimeTypes{'.flx'} = "text/vnd.fmi.flexstor";
        $mimeTypes{'.fmf'} = "video/x-atomic3d-feature";
        $mimeTypes{'.for'} = "text/x-fortran";
        $mimeTypes{'.fpx'} = "image/vnd.net-fpx";
        $mimeTypes{'.frl'} = "application/freeloader";
        $mimeTypes{'.funk'} = "audio/make";
        $mimeTypes{'.g'} = "text/plain";
        $mimeTypes{'.g3'} = "image/g3fax";
        $mimeTypes{'.gif'} = "image/gif";
        $mimeTypes{'.gl'} = "video/x-gl";
        $mimeTypes{'.gsd'} = "audio/x-gsm";
        $mimeTypes{'.gsm'} = "audio/x-gsm";
        $mimeTypes{'.gsp'} = "application/x-gsp";
        $mimeTypes{'.gss'} = "application/x-gss";
        $mimeTypes{'.gtar'} = "application/x-gtar";
        $mimeTypes{'.gz'} = "application/x-gzip";
        $mimeTypes{'.gzip'} = "multipart/x-gzip";
        $mimeTypes{'.h'} = "text/x-h";
        $mimeTypes{'.hdf'} = "application/x-hdf";
        $mimeTypes{'.help'} = "application/x-helpfile";
        $mimeTypes{'.hgl'} = "application/vnd.hp-HPGL";
        $mimeTypes{'.hh'} = "text/x-h";
        $mimeTypes{'.hlb'} = "text/x-script";
        $mimeTypes{'.hlp'} = "application/x-winhelp";
        $mimeTypes{'.hpg'} = "application/vnd.hp-HPGL";
        $mimeTypes{'.hpgl'} = "application/vnd.hp-HPGL";
        $mimeTypes{'.hqx'} = "application/x-mac-binhex40";
        $mimeTypes{'.hta'} = "application/hta";
        $mimeTypes{'.htc'} = "text/x-component";
        $mimeTypes{'.htm'} = "text/html";
        $mimeTypes{'.html'} = "text/html";
        $mimeTypes{'.htmls'} = "text/html";
        $mimeTypes{'.htt'} = "text/webviewhtml";
        $mimeTypes{'.htx '} = "text/html";
        $mimeTypes{'.ice '} = "x-conference/x-cooltalk";
        $mimeTypes{'.ico'} = "image/x-icon";
        $mimeTypes{'.idc'} = "text/plain";
        $mimeTypes{'.ief'} = "image/ief";
        $mimeTypes{'.iefs'} = "image/ief";
        $mimeTypes{'.iges'} = "application/iges";
        $mimeTypes{'.iges '} = "model/iges";
        $mimeTypes{'.igs'} = "model/iges";
        $mimeTypes{'.ima'} = "application/x-ima";
        $mimeTypes{'.imap'} = "application/x-httpd-imap";
        $mimeTypes{'.inf '} = "application/inf";
        $mimeTypes{'.ins'} = "application/x-internett-signup";
        $mimeTypes{'.ip '} = "application/x-ip2";
        $mimeTypes{'.isu'} = "video/x-isvideo";
        $mimeTypes{'.it'} = "audio/it";
        $mimeTypes{'.iv'} = "application/x-inventor";
        $mimeTypes{'.ivr'} = "i-world/i-vrml";
        $mimeTypes{'.ivy'} = "application/x-livescreen";
        $mimeTypes{'.jam '} = "audio/x-jam";
        $mimeTypes{'.jav'} = "text/x-java-source";
        $mimeTypes{'.java'} = "text/plain";
        $mimeTypes{'.java '} = "text/x-java-source";
        $mimeTypes{'.jcm '} = "application/x-java-commerce";
        $mimeTypes{'.jfif'} = "image/pjpeg";
        $mimeTypes{'.jfif-tbnl'} = "image/jpeg";
        $mimeTypes{'.jpe'} = "image/pjpeg";
        $mimeTypes{'.jpeg'} = "image/pjpeg";
        $mimeTypes{'.jpg '} = "image/pjpeg";
        $mimeTypes{'.jps'} = "image/x-jps";
        $mimeTypes{'.js '} = "application/x-javascript";
        $mimeTypes{'.jut'} = "image/jutvision";
        $mimeTypes{'.kar'} = "music/x-karaoke";
        $mimeTypes{'.ksh'} = "text/x-script.ksh";
        $mimeTypes{'.la '} = "audio/x-nspaudio";
        $mimeTypes{'.lam'} = "audio/x-liveaudio";
        $mimeTypes{'.latex '} = "application/x-latex";
        $mimeTypes{'.lha'} = "application/x-lha";
        $mimeTypes{'.lhx'} = "application/octet-stream";
        $mimeTypes{'.list'} = "text/plain";
        $mimeTypes{'.lma'} = "audio/x-nspaudio";
        $mimeTypes{'.log '} = "text/plain";
        $mimeTypes{'.lsp '} = "text/x-script.lisp";
        $mimeTypes{'.lst '} = "text/plain";
        $mimeTypes{'.lsx'} = "text/x-la-asf";
        $mimeTypes{'.ltx'} = "application/x-latex";
        $mimeTypes{'.lzh'} = "application/x-lzh";
        $mimeTypes{'.lzx'} = "application/x-lzx";
        $mimeTypes{'.m'} = "text/x-m";
        $mimeTypes{'.m1v'} = "video/mpeg";
        $mimeTypes{'.m2a'} = "audio/mpeg";
        $mimeTypes{'.m2v'} = "video/mpeg";
        $mimeTypes{'.m3u '} = "audio/x-mpequrl";
        $mimeTypes{'.man'} = "application/x-troff-man";
        $mimeTypes{'.map'} = "application/x-navimap";
        $mimeTypes{'.mar'} = "text/plain";
        $mimeTypes{'.mbd'} = "application/mbedlet";
        $mimeTypes{'.mc$'} = "application/x-magic-cap-package-1.0";
        $mimeTypes{'.mcd'} = "application/x-mathcad";
        $mimeTypes{'.mcf'} = "text/mcf";
        $mimeTypes{'.mcp'} = "application/netmc";
        $mimeTypes{'.me '} = "application/x-troff-me";
        $mimeTypes{'.mht'} = "message/rfc822";
        $mimeTypes{'.mhtml'} = "message/rfc822";
        $mimeTypes{'.mid'} = "x-music/x-midi";
        $mimeTypes{'.midi'} = "x-music/x-midi";
        $mimeTypes{'.mif'} = "application/x-mif";
        $mimeTypes{'.mime '} = "www/mime";
        $mimeTypes{'.mjf'} = "audio/x-vnd.AudioExplosion.MjuiceMediaFi
+le";
        $mimeTypes{'.mjpg '} = "video/x-motion-jpeg";
        $mimeTypes{'.mm'} = "application/x-meme";
        $mimeTypes{'.mme'} = "application/base64";
        $mimeTypes{'.mod'} = "audio/x-mod";
        $mimeTypes{'.moov'} = "video/quicktime";
        $mimeTypes{'.mov'} = "video/quicktime";
        $mimeTypes{'.movie'} = "video/x-sgi-movie";
        $mimeTypes{'.mp2'} = "video/x-mpeq2a";
        $mimeTypes{'.mp3'} = "video/x-mpeg";
        $mimeTypes{'.mpa'} = "video/mpeg";
        $mimeTypes{'.mpc'} = "application/x-project";
        $mimeTypes{'.mpe'} = "video/mpeg";
        $mimeTypes{'.mpeg'} = "video/mpeg";
        $mimeTypes{'.mpg'} = "video/mpeg";
        $mimeTypes{'.mpga'} = "audio/mpeg";
        $mimeTypes{'.mpp'} = "application/vnd.ms-project";
        $mimeTypes{'.mpt'} = "application/x-project";
        $mimeTypes{'.mpv'} = "application/x-project";
        $mimeTypes{'.mpx'} = "application/x-project";
        $mimeTypes{'.mrc'} = "application/marc";
        $mimeTypes{'.ms'} = "application/x-troff-ms";
        $mimeTypes{'.mv'} = "video/x-sgi-movie";
        $mimeTypes{'.my'} = "audio/make";
        $mimeTypes{'.mzz'} = "application/x-vnd.AudioExplosion.mzz";
        $mimeTypes{'.nap'} = "image/naplps";
        $mimeTypes{'.naplps'} = "image/naplps";
        $mimeTypes{'.nc'} = "application/x-netcdf";
        $mimeTypes{'.ncm'} = "application/vnd.nokia.configuration-mess
+age";
        $mimeTypes{'.nif'} = "image/x-niff";
        $mimeTypes{'.niff'} = "image/x-niff";
        $mimeTypes{'.nix'} = "application/x-mix-transfer";
        $mimeTypes{'.nsc'} = "application/x-conference";
        $mimeTypes{'.nvd'} = "application/x-navidoc";
        $mimeTypes{'.o'} = "application/octet-stream";
        $mimeTypes{'.oda'} = "application/oda";
        $mimeTypes{'.omc'} = "application/x-omc";
        $mimeTypes{'.omcd'} = "application/x-omcdatamaker";
        $mimeTypes{'.omcr'} = "application/x-omcregerator";
        $mimeTypes{'.p'} = "text/x-pascal";
        $mimeTypes{'.p10'} = "application/x-pkcs10";
        $mimeTypes{'.p12'} = "application/x-pkcs12";
        $mimeTypes{'.p7a'} = "application/x-pkcs7-signature";
        $mimeTypes{'.p7c'} = "application/x-pkcs7-mime";
        $mimeTypes{'.p7m'} = "application/x-pkcs7-mime";
        $mimeTypes{'.p7r'} = "application/x-pkcs7-certreqresp";
        $mimeTypes{'.p7s'} = "application/pkcs7-signature";
        $mimeTypes{'.part '} = "application/pro_eng";
        $mimeTypes{'.pas'} = "text/pascal";
        $mimeTypes{'.pbm '} = "image/x-portable-bitmap";
        $mimeTypes{'.pcl'} = "application/x-pcl";
        $mimeTypes{'.pct'} = "image/x-pict";
        $mimeTypes{'.pcx'} = "image/x-pcx";
        $mimeTypes{'.pdb'} = "chemical/x-pdb";
        $mimeTypes{'.pdf'} = "application/pdf";
        $mimeTypes{'.pfunk'} = "audio/make.my.funk";
        $mimeTypes{'.pgm'} = "image/x-portable-greymap";
        $mimeTypes{'.pic'} = "image/pict";
        $mimeTypes{'.pict'} = "image/pict";
        $mimeTypes{'.pkg'} = "application/x-newton-compatible-pkg";
        $mimeTypes{'.pko'} = "application/vnd.ms-pki.pko";
        $mimeTypes{'.pl'} = "text/x-script.perl";
        $mimeTypes{'.plx'} = "application/x-PiXCLscript";
        $mimeTypes{'.pm'} = "text/x-script.perl-module";
        $mimeTypes{'.pm4 '} = "application/x-pagemaker";
        $mimeTypes{'.pm5'} = "application/x-pagemaker";
        $mimeTypes{'.png'} = "image/png";
        $mimeTypes{'.pnm'} = "image/x-portable-anymap";
        $mimeTypes{'.pot'} = "application/vnd.ms-powerpoint";
        $mimeTypes{'.pov'} = "model/x-pov";
        $mimeTypes{'.ppa'} = "application/vnd.ms-powerpoint";
        $mimeTypes{'.ppm'} = "image/x-portable-pixmap";
        $mimeTypes{'.pps'} = "application/vnd.ms-powerpoint";
        $mimeTypes{'.ppt'} = "application/x-mspowerpoint";
        $mimeTypes{'.ppz'} = "application/mspowerpoint";
        $mimeTypes{'.pre'} = "application/x-freelance";
        $mimeTypes{'.prt'} = "application/pro_eng";
        $mimeTypes{'.ps'} = "application/postscript";
        $mimeTypes{'.psd'} = "application/octet-stream";
        $mimeTypes{'.pvu'} = "paleovu/x-pv";
        $mimeTypes{'.pwz '} = "application/vnd.ms-powerpoint";
        $mimeTypes{'.py '} = "text/x-script.phyton";
        $mimeTypes{'.pyc '} = "applicaiton/x-bytecode.python";
        $mimeTypes{'.qcp '} = "audio/vnd.qcelp";
        $mimeTypes{'.qd3 '} = "x-world/x-3dmf";
        $mimeTypes{'.qd3d '} = "x-world/x-3dmf";
        $mimeTypes{'.qif'} = "image/x-quicktime";
        $mimeTypes{'.qt'} = "video/quicktime";
        $mimeTypes{'.qtc'} = "video/x-qtc";
        $mimeTypes{'.qti'} = "image/x-quicktime";
        $mimeTypes{'.qtif'} = "image/x-quicktime";
        $mimeTypes{'.ra'} = "audio/x-realaudio";
        $mimeTypes{'.ram'} = "audio/x-pn-realaudio";
        $mimeTypes{'.ras'} = "image/x-cmu-raster";
        $mimeTypes{'.rast'} = "image/cmu-raster";
        $mimeTypes{'.rexx '} = "text/x-script.rexx";
        $mimeTypes{'.rf'} = "image/vnd.rn-realflash";
        $mimeTypes{'.rgb '} = "image/x-rgb";
        $mimeTypes{'.rm'} = "audio/x-pn-realaudio";
        $mimeTypes{'.rmi'} = "audio/mid";
        $mimeTypes{'.rmm '} = "audio/x-pn-realaudio";
        $mimeTypes{'.rmp'} = "audio/x-pn-realaudio-plugin";
        $mimeTypes{'.rng'} = "application/vnd.nokia.ringing-tone";
        $mimeTypes{'.rnx '} = "application/vnd.rn-realplayer";
        $mimeTypes{'.roff'} = "application/x-troff";
        $mimeTypes{'.rp '} = "image/vnd.rn-realpix";
        $mimeTypes{'.rpm'} = "audio/x-pn-realaudio-plugin";
        $mimeTypes{'.rt'} = "text/vnd.rn-realtext";
        $mimeTypes{'.rtf'} = "text/richtext";
        $mimeTypes{'.rtx'} = "text/richtext";
        $mimeTypes{'.rv'} = "video/vnd.rn-realvideo";
        $mimeTypes{'.s'} = "text/x-asm";
        $mimeTypes{'.s3m '} = "audio/s3m";
        $mimeTypes{'.saveme'} = "application/octet-stream";
        $mimeTypes{'.sbk '} = "application/x-tbook";
        $mimeTypes{'.scm'} = "video/x-scm";
        $mimeTypes{'.sdml'} = "text/plain";
        $mimeTypes{'.sdp '} = "application/x-sdp";
        $mimeTypes{'.sdr'} = "application/sounder";
        $mimeTypes{'.sea'} = "application/x-sea";
        $mimeTypes{'.set'} = "application/set";
        $mimeTypes{'.sgm '} = "text/x-sgml";
        $mimeTypes{'.sgml'} = "text/x-sgml";
        $mimeTypes{'.sh'} = "text/x-script.sh";
        $mimeTypes{'.shar'} = "application/x-shar";
        $mimeTypes{'.shtml'} = "text/x-server-parsed-html";
        $mimeTypes{'.shtml '} = "text/html";
        $mimeTypes{'.sid'} = "audio/x-psid";
        $mimeTypes{'.sit'} = "application/x-stuffit";
        $mimeTypes{'.skd'} = "application/x-koan";
        $mimeTypes{'.skm '} = "application/x-koan";
        $mimeTypes{'.skp '} = "application/x-koan";
        $mimeTypes{'.skt '} = "application/x-koan";
        $mimeTypes{'.sl '} = "application/x-seelogo";
        $mimeTypes{'.smi '} = "application/smil";
        $mimeTypes{'.smil '} = "application/smil";
        $mimeTypes{'.snd'} = "audio/x-adpcm";
        $mimeTypes{'.sol'} = "application/solids";
        $mimeTypes{'.spc '} = "text/x-speech";
        $mimeTypes{'.spl'} = "application/futuresplash";
        $mimeTypes{'.spr'} = "application/x-sprite";
        $mimeTypes{'.sprite '} = "application/x-sprite";
        $mimeTypes{'.src'} = "application/x-wais-source";
        $mimeTypes{'.ssi'} = "text/x-server-parsed-html";
        $mimeTypes{'.ssm '} = "application/streamingmedia";
        $mimeTypes{'.sst'} = "application/vnd.ms-pki.certstore";
        $mimeTypes{'.step'} = "application/step";
        $mimeTypes{'.stl'} = "application/x-navistyle";
        $mimeTypes{'.stp'} = "application/step";
        $mimeTypes{'.sv4cpio'} = "application/x-sv4cpio";
        $mimeTypes{'.sv4crc'} = "application/x-sv4crc";
        $mimeTypes{'.svf'} = "image/x-dwg";
        $mimeTypes{'.svr'} = "x-world/x-svr";
        $mimeTypes{'.swf'} = "application/x-shockwave-flash";
        $mimeTypes{'.t'} = "application/x-troff";
        $mimeTypes{'.talk'} = "text/x-speech";
        $mimeTypes{'.tar'} = "application/x-tar";
        $mimeTypes{'.tbk'} = "application/x-tbook";
        $mimeTypes{'.tcl'} = "text/x-script.tcl";
        $mimeTypes{'.tcsh'} = "text/x-script.tcsh";
        $mimeTypes{'.tex'} = "application/x-tex";
        $mimeTypes{'.texi'} = "application/x-texinfo";
        $mimeTypes{'.texinfo'} = "application/x-texinfo";
        $mimeTypes{'.text'} = "text/plain";
        $mimeTypes{'.tgz'} = "application/x-compressed";
        $mimeTypes{'.tif'} = "image/x-tiff";
        $mimeTypes{'.tiff'} = "image/x-tiff";
        $mimeTypes{'.tr'} = "application/x-troff";
        $mimeTypes{'.tsi'} = "audio/tsp-audio";
        $mimeTypes{'.tsp'} = "audio/tsplayer";
        $mimeTypes{'.tsv'} = "text/tab-separated-values";
        $mimeTypes{'.turbot'} = "image/florian";
        $mimeTypes{'.txt'} = "text/plain";
        $mimeTypes{'.uil'} = "text/x-uil";
        $mimeTypes{'.uni'} = "text/uri-list";
        $mimeTypes{'.unis'} = "text/uri-list";
        $mimeTypes{'.unv'} = "application/i-deas";
        $mimeTypes{'.uri'} = "text/uri-list";
        $mimeTypes{'.uris'} = "text/uri-list";
        $mimeTypes{'.ustar'} = "multipart/x-ustar";
        $mimeTypes{'.uu'} = "text/x-uuencode";
        $mimeTypes{'.uue'} = "text/x-uuencode";
        $mimeTypes{'.vcd'} = "application/x-cdlink";
        $mimeTypes{'.vcs'} = "text/x-vCalendar";
        $mimeTypes{'.vda'} = "application/vda";
        $mimeTypes{'.vdo'} = "video/vdo";
        $mimeTypes{'.vew '} = "application/groupwise";
        $mimeTypes{'.viv'} = "video/vnd.vivo";
        $mimeTypes{'.vivo'} = "video/vnd.vivo";
        $mimeTypes{'.vmd '} = "application/vocaltec-media-desc";
        $mimeTypes{'.vmf'} = "application/vocaltec-media-file";
        $mimeTypes{'.voc'} = "audio/x-voc";
        $mimeTypes{'.vos'} = "video/vosaic";
        $mimeTypes{'.vox'} = "audio/voxware";
        $mimeTypes{'.vqe'} = "audio/x-twinvq-plugin";
        $mimeTypes{'.vqf'} = "audio/x-twinvq";
        $mimeTypes{'.vql'} = "audio/x-twinvq-plugin";
        $mimeTypes{'.vrml'} = "x-world/x-vrml";
        $mimeTypes{'.vrt'} = "x-world/x-vrt";
        $mimeTypes{'.vsd'} = "application/x-visio";
        $mimeTypes{'.vst'} = "application/x-visio";
        $mimeTypes{'.vsw '} = "application/x-visio";
        $mimeTypes{'.w60'} = "application/wordperfect6.0";
        $mimeTypes{'.w61'} = "application/wordperfect6.1";
        $mimeTypes{'.w6w'} = "application/msword";
        $mimeTypes{'.wav'} = "audio/x-wav";
        $mimeTypes{'.wb1'} = "application/x-qpro";
        $mimeTypes{'.wbmp'} = "image/vnd.wap.wbmp";
        $mimeTypes{'.web'} = "application/vnd.xara";
        $mimeTypes{'.wiz'} = "application/msword";
        $mimeTypes{'.wk1'} = "application/x-123";
        $mimeTypes{'.wmf'} = "windows/metafile";
        $mimeTypes{'.wml'} = "text/vnd.wap.wml";
        $mimeTypes{'.wmlc '} = "application/vnd.wap.wmlc";
        $mimeTypes{'.wmls'} = "text/vnd.wap.wmlscript";
        $mimeTypes{'.wmlsc '} = "application/vnd.wap.wmlscriptc";
        $mimeTypes{'.word '} = "application/msword";
        $mimeTypes{'.wp'} = "application/wordperfect";
        $mimeTypes{'.wp5'} = "application/wordperfect6.0";
        $mimeTypes{'.wp6 '} = "application/wordperfect";
        $mimeTypes{'.wpd'} = "application/x-wpwin";
        $mimeTypes{'.wq1'} = "application/x-lotus";
        $mimeTypes{'.wri'} = "application/x-wri";
        $mimeTypes{'.wrl'} = "x-world/x-vrml";
        $mimeTypes{'.wrz'} = "x-world/x-vrml";
        $mimeTypes{'.wsc'} = "text/scriplet";
        $mimeTypes{'.wsrc'} = "application/x-wais-source";
        $mimeTypes{'.wtk '} = "application/x-wintalk";
        $mimeTypes{'.x-png'} = "image/png";
        $mimeTypes{'.xbm'} = "image/xbm";
        $mimeTypes{'.xdr'} = "video/x-amt-demorun";
        $mimeTypes{'.xgz'} = "xgl/drawing";
        $mimeTypes{'.xif'} = "image/vnd.xiff";
        $mimeTypes{'.xl'} = "application/excel";
        $mimeTypes{'.xla'} = "application/x-msexcel";
        $mimeTypes{'.xlb'} = "application/x-excel";
        $mimeTypes{'.xlc'} = "application/x-excel";
        $mimeTypes{'.xld '} = "application/x-excel";
        $mimeTypes{'.xlk'} = "application/x-excel";
        $mimeTypes{'.xll'} = "application/x-excel";
        $mimeTypes{'.xlm'} = "application/x-excel";
        $mimeTypes{'.xls'} = "application/x-msexcel";
        $mimeTypes{'.xlt'} = "application/x-excel";
        $mimeTypes{'.xlv'} = "application/x-excel";
        $mimeTypes{'.xlw'} = "application/x-msexcel";
        $mimeTypes{'.xm'} = "audio/xm";
        $mimeTypes{'.xml'} = "text/xml";
        $mimeTypes{'.xmz'} = "xgl/movie";
        $mimeTypes{'.xpix'} = "application/x-vnd.ls-xpix";
        $mimeTypes{'.xpm'} = "image/xpm";
        $mimeTypes{'.xsr'} = "video/x-amt-showrun";
        $mimeTypes{'.xwd'} = "image/x-xwindowdump";
        $mimeTypes{'.xyz'} = "chemical/x-pdb";
        $mimeTypes{'.z'} = "application/x-compressed";
        $mimeTypes{'.zip'} = "multipart/x-zip";
        $mimeTypes{'.zoo'} = "application/octet-stream";
        $mimeTypes{'.zsh'} = "text/x-script.zsh";

        if ( ! exists($mimeTypes{".$extension"})) { return "unknown"; 
+}
        else {
            return $mimeTypes{".$extension"};
        }

}

# ====================================================================
+====
#  _ p a r s e A d d r e s s( )
#
sub _parseAddress($) {
    my ($self, $thisAddress) = @_;
    if ( $thisAddress =~ /<(.*?)>/ ) {
        return ( "$1", "$thisAddress" );
    } else {
        return ( "$thisAddress", "$thisAddress" );
    }
}

# ====================================================================
+====
# D E P R E C A T E D
# ====================================================================
+====
# p a r a m s
#
# The old way to set parameters for the email - doesn't support multip
+le addresses, cc's or bcc's.

sub params {
    my $self = shift;
    my $paramString = shift;

        # Parse the parameter string
        my ($to) = ( $paramString =~ /to=([^;]+)/i );
        my ($from) = ( $paramString =~ /from=([^;]+)/i );
        my ($subject) = ( $paramString =~ /subject=([^;]+)/i );
        my ($ip) = ( $paramString =~ /mailserver=([^;]+)/i );

        # Store the values
        $self->to( $to );
        $self->from( $from );
        $self->subject($subject) if $subject;
        $self->smtpServer($ip) if ( $ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\
+.\d{1,3}/ );

    return;
}

# ====================================================================
+====
# set_plaintext
#
# Deprecated wrapper for "text()"

sub set_plaintext {
    my $self = shift;
    my $text = shift;
        $self->text($text);
    return;
}

# ====================================================================
+====
# s e t _ h t m l t e x t
#
# Deprecated wrapper for "html()"

sub set_htmltext {
    my $self = shift;
    my $html = shift;
        $self->text($html);
    return;
}

# ====================================================================
+====
# s e t _ d e b u g
#
# Deprecated wrapper for "debug()"

sub set_debug {
    my ($self, $debug) = @_;
    $self->debug($debug);
    return;
}

# ====================================================================
+====
# l o g _ t o _ s c r e e n ( )

sub log_to_screen {
    return;
}

# ====================================================================
+====
# s e n d m a i l ( )
#
# A wrapper for prefered sendMail()

sub sendmail {
    @_[0]->sendMail();
}

# ====================================================================
+====

1;

__END__

# ====================================================================
+====
# D O C U M E N T A T I O N
#
# Only POD beyond this point....

=head1 TITLE

JMailer

=for html <style type="text/css">
body { font-family: arial, verdana, helevetica, sans-serif; }
h3  {border-bottom: 1px solid #000000; }
</style>

=head1 PRE-REQUISITES

    Net::SMTP;
    MIME::Base64;

=head1 SYNOPSIS

    $mail = JMailer->new();

    $mail->to( 'John Gregory <john@johngregory.me.uk>' );
    $mail->from( 'John Gregory <jayae.geo@yahoo.com>' );
    $mail->cc( 'someone@here.com', 'someoneelse@theirisp.co.uk' );

    $mail->subject( 'Make $$$ in your spare time from home!!!!!' );
    $mail->smtpServer( '192.168.2.70' );
    
    $mail->attachment( "somedir/internaldir/addme.doc" );

    $mail->debug(1);

    $success = $mail->sendMail();

=head1 DESCRIPTION

JMailer is an simple object orientated SMTP based e-mail module.

The API is designed to be as user friendly and simple to use as possib
+le, making it just as easy to send text/html encoded
e-mails complete with encoded in-line images as it is to send plain te
+xt.

In an effort to be as compatable with as many e-mail user agents as po
+ssible, the resultant e-mail message body is polymorphic
and only builds in the pieces necessary to send the required e-mail. I
+n essence, the simpler the e-mail, the more compatable it's likely
to be.

Message bodies are based on the standard Internet message and MIME RFC
+s.

=head1 RELEASE NOTES

=over

=item * (Version 2.0)

B<SMTP Update> - The old C<Net::Telnet> connection has been replaced b
+y the smoother C<Net::SMTP>.

B<Deprecation and removed> - Most old methods are still supported, but
+ deprecated (see list). There are
alternatives for all deprecated methods. Please see individual docs fo
+r the recommended changes.

B<Polymorphic Mail Content> - Before you used to get those annoying "a
+ttachment" symbols turning up on emails that
didn't have any files attached and such like; not to mention incompata
+bility issues. To this end, the internal message
structure now ONLY contains EXACTLY what it needs for the content ente
+red. This should mean that, the simpler the
message, the more guraranteed it is to be compatable with the widest r
+ange of systems.

B<Attachment Filenames Fixed> - The filenames have been fixed so that 
+if an attachment is referenced via a path instead of
in the local directory, the resulting name will be the correct name of
+ the file and not the first folder in the path. e.g.

    $mail->attachment( "emaildata/client/myfile.txt" );

.. will now correctly display in the resulting email as "myfile.txt" i
+nstead of "emaildata" as would previously happen.

B<Base64 only used where needed> - Plain ASCII text files were encount
+ering problems when being encoded. As such
if a file is found to be .txt it is not encoded and is included with a
+ different header sequence. This appears to have fixed
the problem.

=back

=head1 METHODS

=head2 API

=head3 new

C<new()>

Class constructor. Called to create a new instance of this class - a n
+ew "mail" object.

=head3 to, cc, bcc

C<[hashref] <methodname>( <addresslist> )>

All three of C<to()>, C<cc()> and C<bcc()> work in the same way. All o
+f the methods take a list of addresses as
an argument and replace any already set addresses with the new address
+es. When called without an argument list,
the method will return the hashref containing currently set addresses.

Entered addresses may be in the form either:

someone@address.com

or

A. N. Other <someone@address.com>

Don't quote the name unless you want the quotes to appear on the resul
+ting email!

B<NB> Only C<to()> is mandatory for sending an email.

=head3 from

C<[hashref] from( <address> )

Sets the C<from> address for the email - there can only be a single C<
+from> address and so the method only
takes a single string as an argument (May contain an alias in the same
+ was as for C<to()>). Like the other address methods, calling with an
+ argument will reset the
current value (if any) with the new value and if called without will s
+imply return the current value (if any) as a
hashref.

=head3 attachment

C<[void] attachment( <filename> )>

Simply call with the uri of the file you wish to attach relative to th
+e script that runs JMailer.

    $mail->attachment( "emaildata/subfolder/myfile.txt" );

All attachments (with the exception of *.txt files) are base64 encoded
+ using the C<MIME::Base64> module
before attaching. Encoding *.txt files would lead to corruption of tho
+se files.

=head3 subject

C<[string] subject( <subjectline> )>

Sets the subject line of the email. Returns the current / new subject 
+line whether called with or without an argument.

=head3 smtpServer

C<[string] smtpServer( <ip> )>

Takes an IP address for the SMTP mail server that you wish to relay yo
+ur messages through. Returns the current / new
IP address. (I<required>)

=head3 text

C<[void] text( <emailText> )>

Sets the plain text body of an email (I<required>)

=head3 html

C<[void] html( <emailHtmlText> )>

Sets the HTML text body of an email.

=head3 sendMail

C<[int] sendMail()>

Sends the email built using the other methods. Returns a boolean succe
+ss value.

=head3 debug

Switches on the debugging of the underlying C<Net::SMTP> module.

=head2 INTERNAL

Never call any of these directly from a script. These are included in 
+the docs for reference and future development.

=head3 _smtp

The wrapper for the call to Net::SMTP that handles the server interact
+ion.

=head3 _buildMessage

Calls the C<_wrapXX()> methods in sequence (depending on required cont
+ent) to construct the internal
mail message structure.

=head3 _getFormattedDate

Returns a current date string in email-friendly compliant format.

=head3 _prepareHtml

Parses the stored HTML text and encodes any inline images found within
+. These are then stored in
C<{'EMBEDDED_IMAGE_ENCODINGS'}>.

=head3 _prepareAttachment

For each specified attachment, determines the content type ( with C<_g
+etMIME()> ) and Base64 encodes
( using C<_encode64()> ) if required (all except plain text files).

Adds correct header block and boundary marks and stores in C<{'ENCODED
+_ATTACHMENTS'}>.

=head3 _encode64

A wrapper for the function call to C<MIME::Base64>. Used by C<_prepare
+Attachment()> and C<_prepareHtml()>.

=head3 _wrapPlainText

The first call from C<_buildMessage>. Wraps the stored plaintext with 
+the correct headers.

=head3 _wrapHtml

Wraps the stored HTML text with the correct headers and wraps around t
+he plain text already encoded with C<_wrapPlainText()>.

=head3 _wrapInline

Called after C<_wrapHtml()> if there are inline images in the C<{'EMBE
+DDED_IMAGE_ENCODINGS'}> list. Adds
an outer set of boundaries with the C<multiplart/related> content type
+ around the output of C<_wrapHtml()>.

=head3 _wrapAttach

Called last, wraps the complete message (built with the combination of
+ the C<_wrapXX()> methods above) with the
C<multipart/mixed> boundaries and adds in the attachment encodings fro
+m C<{'ENCODDED_ATTACMENTS'}>.

=head3 _getMIME

Parses a given file extension and returns a string with the correct MI
+ME type.

=head3 _parseAddress

Parses a given email address string into address and alias (if there i
+s one), returning the results. If there is no alias,
the email address is passed back in it's place as a "pseudo alias".

=head1 AUTHOR

J. Gregory <john@johngregory.me.uk>

=cut