package JMailer; require 5.6.0; use strict; our $VERSION = '2.0'; our $AUTHOR = 'J. Gregory '; 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->ServerVariables('PATH_INFO')); # Strip the script name.... $here =~ s/(.*\\).*/$1/g; # chdir so we're pointing at the right "base" for uploads 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 originial 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 value 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'}, Timeout => 40, Hello => "$client", Debug=>"$self->{'DEBUG'}"); if ( ! $smtp ) { return 0; } # No object created - return 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->bcc($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 there 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 "alternative" 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//g; $messageTemp =~ s/\s/ /g; $messageTemp =~ s/\[(\/?b)\]/<$1>/g; close(MSG); $self->{'MESSAGE'} = $message; # Store the completed message 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) = localtime(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$bst"; 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 "inline" - will be imported into the eMail my $image_name = undef; my $count = 0; # Counter used when encoding the 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 tags from the text (@image_tags) = ( ${$html_text_ref} =~ /()/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 encode 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, and 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: base64\n"; $encodedImage .= "Content-Disposition: inline; filename=\"$cleanName\"\n"; $encodedImage .= "Content-ID: "; $encodedImage .= "\n\n"; $encodedImage .= $self->_encode64(\$inline_image); 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() { $filedata .= $_; } close(IN); $attachment .= "Content-Type: text/plain; charset=\"us-ascii\"\n"; $attachment .= "Content-Disposition: attachment; filename=\"$cleanName\""; $attachment .= "\n\n"; $attachment .= $filedata; push @{$self->{'ENCODED_ATTACHMENTS'}}, $attachment; return 1; } else { if ($base64encoded = $self->_encode64($fileref)) { $attachment .= "Content-Type: $type; name=\"$cleanName\"\n"; $attachment .= "Content-Transfer-Encoding: Base64\n"; $attachment .= "Content-Disposition: attachment; filename=\"$cleanName\""; $attachment .= "\n\n"; $attachment .= $base64encoded; push @{$self->{'ENCODED_ATTACHMENTS'}}, $attachment; 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 off 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==.MIX"; --================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-add-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.MjuiceMediaFile"; $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-message"; $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 multiple 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 =head1 PRE-REQUISITES Net::SMTP; MIME::Base64; =head1 SYNOPSIS $mail = JMailer->new(); $mail->to( 'John Gregory ' ); $mail->from( 'John Gregory ' ); $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 possible, making it just as easy to send text/html encoded e-mails complete with encoded in-line images as it is to send plain text. In an effort to be as compatable with as many e-mail user agents as possible, the resultant e-mail message body is polymorphic and only builds in the pieces necessary to send the required e-mail. In 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 RFCs. =head1 RELEASE NOTES =over =item * (Version 2.0) B - The old C connection has been replaced by the smoother C. B - Most old methods are still supported, but deprecated (see list). There are alternatives for all deprecated methods. Please see individual docs for the recommended changes. B - Before you used to get those annoying "attachment" symbols turning up on emails that didn't have any files attached and such like; not to mention incompatability issues. To this end, the internal message structure now ONLY contains EXACTLY what it needs for the content entered. This should mean that, the simpler the message, the more guraranteed it is to be compatable with the widest range of systems. B - 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" instead of "emaildata" as would previously happen. B - Plain ASCII text files were encountering 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 Class constructor. Called to create a new instance of this class - a new "mail" object. =head3 to, cc, bcc C<[hashref] ( )> All three of C, C and C work in the same way. All of the methods take a list of addresses as an argument and replace any already set addresses with the new addresses. 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 Don't quote the name unless you want the quotes to appear on the resulting email! B Only C is mandatory for sending an email. =head3 from C<[hashref] from(
) Sets the C address for the email - there can only be a single C address and so the method only takes a single string as an argument (May contain an alias in the same was as for C). 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 simply return the current value (if any) as a hashref. =head3 attachment C<[void] attachment( )> Simply call with the uri of the file you wish to attach relative to the script that runs JMailer. $mail->attachment( "emaildata/subfolder/myfile.txt" ); All attachments (with the exception of *.txt files) are base64 encoded using the C module before attaching. Encoding *.txt files would lead to corruption of those files. =head3 subject C<[string] subject( )> 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( )> Takes an IP address for the SMTP mail server that you wish to relay your messages through. Returns the current / new IP address. (I) =head3 text C<[void] text( )> Sets the plain text body of an email (I) =head3 html C<[void] html( )> Sets the HTML text body of an email. =head3 sendMail C<[int] sendMail()> Sends the email built using the other methods. Returns a boolean success value. =head3 debug Switches on the debugging of the underlying C 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 interaction. =head3 _buildMessage Calls the C<_wrapXX()> methods in sequence (depending on required content) 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<_getMIME()> ) 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. Used by C<_prepareAttachment()> 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 the plain text already encoded with C<_wrapPlainText()>. =head3 _wrapInline Called after C<_wrapHtml()> if there are inline images in the C<{'EMBEDDED_IMAGE_ENCODINGS'}> list. Adds an outer set of boundaries with the C 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 boundaries and adds in the attachment encodings from C<{'ENCODDED_ATTACMENTS'}>. =head3 _getMIME Parses a given file extension and returns a string with the correct MIME type. =head3 _parseAddress Parses a given email address string into address and alias (if there is 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 =cut