package EasyMail;
use strict;
use warnings(FATAL=>'all');
our $VERSION = '2.5.2';
#===================================
#===Module : 43f01b295f6fcfca
#===Version : 43f01b600bc33f65
#===================================
#===================================
#===Module : Framework::EasyMail
#===File : lib/Framework/EasyMail.pm
#===Comment : a lib to send email
#===Require : File::Basename MIME::Base64 FileHandle IO::Socket::INET Time::Local Encode
#===================================
#===================================
#===Author : qian.yu ===
#===Email : foolfish@cpan.org ===
#===MSN : qian.yu@adways.net ===
#===QQ : 9097939 ===
#===Homepage: www.fishlib.cn ===
#===================================
#=======================================
#===Author : huang.shuai ===
#===Email : huang.shuai@adways.net ===
#===MSN : huang.shuai@adways.net ===
#=======================================
#BUG
# * Return-Path is not function in sendmail daemon(not qmail daemon), for further help contact author
#Future Request:
#===2.5.2(2008-12-08): fix bug "http://rt.cpan.org/Ticket/Display.html?id=34032",thanks to "Ursetti, Jerry" find this bug
#===2.5.1(2008-07-16): fix bug when traslate charset from utf8 to iso-2022-jp
# (2008-05-08): fix bug on dst = 'un'
#===2.5.0(2008-03-12): add DIRECT send type,if you use DIRECT module "Net::DNS" is required
#===2.4.4(2007-10-10): modify X-Mailer, remove Thread-Index and X-MimeOLE, fix BCC bug
#===2.4.3(2006-08-28): fix parse mail list bugs
#===2.4.2(2006-08-17): fix filter bugs
#===2.4.1(2006-08-01): add email filter
#===2.4.0(2006-07-31): document format
#===2.3.0(2005-08-18): smtp support, non-ascii attachment file name support
#===2.0.1(2005-08-12): modified _sendmail, die if sendmail_path not valid
#===2.0.0(2005-08-12): second version release, Simplify the first version, and add some function
use File::Basename;
use MIME::Base64;
use FileHandle;
use IO::Socket::INET;
use Time::Local;
use Encode;
sub foo{1};
sub _name_pkg_name{'EasyMail'}
sub _name_true{1;}
sub _name_false{'';}
my $_max_file_len = 100000000;
my $_all_ascii=&_name_true;
#===$str=trim($str)
#===delete blank before and after $str, return undef if $str is undef
sub trim($) {
my $param_count=scalar(@_);
if($param_count==1){
local $_=$_[0];
unless(defined($_)){return undef;}
s/^\s+//,s/\s+$//;
return $_ ;
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'trim: param count should be 1');
}
}
#===$flag=is_email($id)
#===check whether a valid email address
sub is_email($){
my $param_count=scalar(@_);
if($param_count==1){
local $_=$_[0];
if(!defined($_)){
return defined(&_name_false)?&_name_false:'';
}elsif(/^[a-zA-Z0-9\_\.\-]+\@([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/){
return defined(&_name_true)?&_name_true:1;
}else{
return defined(&_name_false)?&_name_false:'';
}
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'is_email: param count should be 1');
}
}
#===generate a unique mime_boundary string
sub gen_mime_boundary($){
'------------06010007000403080202'.(shift);
}
#===guess file content type from it's name
sub guess_file_content_type($){
my($filename)=@_;
if(!defined($filename)){return undef;}
my $map={
'au' => 'audio/basic',
'avi' => 'video/x-msvideo',
'class' => 'application/octet-stream',
'cpt' => 'application/mac-compactpro',
'dcr' => 'application/x-director',
'dir' => 'application/x-director',
'doc' => 'application/msword',
'exe' => 'application/octet-stream',
'gif' => 'image/gif',
'gtx' => 'application/x-gentrix',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'js' => 'application/x-javascript',
'hqx' => 'application/mac-binhex40',
'htm' => 'text/html',
'html' => 'text/html',
'mid' => 'audio/midi',
'midi' => 'audio/midi',
'mov' => 'video/quicktime',
'mp2' => 'audio/mpeg',
'mp3' => 'audio/mpeg',
'mpeg' => 'video/mpeg',
'mpg' => 'video/mpeg',
'pdf' => 'application/pdf',
'pm' => 'text/plain',
'pl' => 'text/plain',
'ppt' => 'application/powerpoint',
'ps' => 'application/postscript',
'qt' => 'video/quicktime',
'ram' => 'audio/x-pn-realaudio',
'rtf' => 'application/rtf',
'tar' => 'application/x-tar',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'txt' => 'text/plain',
'wav' => 'audio/x-wav',
'xbm' => 'image/x-xbitmap',
'zip' => 'application/zip'
};
my ($base,$path,$type) = File::Basename::fileparse($filename,qr{\..*});
if($type){$type=lc(substr($type,1))};
$map->{$type} or 'application/octet-stream';
}
#===use base64 to encode header
sub _encode_b($$){
my($str,$encoding)=@_;
'=?'.$encoding.'?B?'.MIME::Base64::encode_base64($str,'').'?=';
}
#===cut the str into specified length
sub _my_chunk_split($$$){
my ($str,$line_delimiter,$line_len)=@_;
my $len=length($str);
my $out='';
while ($len>0){
if ($len>=$line_len){
$out.=substr($str,0,$line_len).$line_delimiter;
$str=substr($str,$line_len);
$len=$len-$line_len;
}else{
$out.=$str.$line_delimiter;
$str='';
$len=0;
}
}
$out;
}
sub change_encoding($$$){
if(defined(&utf8::is_utf8)&&utf8::is_utf8($_[0])){
return Encode::encode($_[2],$_[0]);
}elsif($_[0]=~/^[\040-\176\r\t\n]*$/){
#no need to do anything if all ascii
return $_[0];
}elsif(defined($_[1])&&defined($_[2])&&($_[1] eq $_[2])){
#no need to do anything if $src_encoding=$dst_encoding
return $_[0];
}elsif(defined($_[1])&&defined($_[2])&&($_[1] ne $_[2])){
if ($_[1] eq 'utf8' and $_[2] eq 'iso-2022-jp') {
eval {
require Unicode::Japanese;
};
if ($@) {
return Encode::encode($_[2],Encode::decode($_[1],$_[0]));
} else {
return Unicode::Japanese->new($_[0])->jis;
}
} else {
return Encode::encode($_[2],Encode::decode($_[1],$_[0]));
}
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: you must set src_encoding');
}
}
#===encoder header
sub encode_header($$$$){
my ($str,$src_encoding,$dst_encoding,$dst_encoding_txt)=@_;
#change encoding
$str=change_encoding($str,$src_encoding,$dst_encoding);
if($str=~/^[\040-\176]*$/){
#if all ascii, no need to encode
}else{
$str=_encode_b($str,$dst_encoding_txt);
$_all_ascii=&_name_false;
}
$str;
}
#===gen header
sub gen_header($$$){
my ($key,$value,$line_delimiter)=@_;
return defined($value)?$key.': '.$value.$line_delimiter:'';
}
#===gen "Bill Gates" <gates@hotmail.com>
sub gen_email_name_pair($$$$$){
my ($email,$name,$src_encoding,$dst_encoding,$dst_encoding_txt)=@_;
if(!is_email($email)){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: not a valid email address');
}
#if no from_name ,just return it
if(!defined($name)){return ($email,$email);}
#change encoding
$name=encode_header($name,$src_encoding,$dst_encoding,$dst_encoding_txt);
$name=~s/([\\\"])/\\$1/g;
return ("\"$name\" <$email>",$email);
}
sub parse_email_name_pair($){
my ($email_name_pair)=@_;
my ($email,$name);
my $type=ref $email_name_pair;
if(($type eq '')&&(defined($email_name_pair))){
local $_=$email_name_pair;
s/^\s+//,s/\s+$//;
if(/^[a-zA-Z0-9\_\.\-]+\@([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/){
return ($_,undef);
}elsif(/^([^\s](.*[^\s])?)[\s]+([a-zA-Z0-9\_\.\-]+\@([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6})$/){
return ($3,$1);
}elsif(/^([a-zA-Z0-9\_\.\-]+\@([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6})[\s]+([^\s](.*[^\s])?)$/){
return ($1,$4);
}elsif(/^[\"](.*)[\"][\s]*[\<][\s]*([a-zA-Z0-9\_\.\-]+\@([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6})[\s]*[\>]$/){
return ($2,$1);
}elsif(/^([^\s](.*[^\s])?)[\s]*[\<][\s]*([a-zA-Z0-9\_\.\-]+\@([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6})[\s]*[\>]$/){
return ($3,$1);
}else{
return (undef,undef);
}
}elsif($type eq 'ARRAY'){
if((ref($email_name_pair->[0]) eq '')&& (ref($email_name_pair->[1]) eq '')){
my ($A,$B)=(trim($email_name_pair->[0]),trim($email_name_pair->[1]));
if(is_email($A)){
if(defined($B) &&($B eq '')){$B =undef;}
return ($A,$B);
}elsif(is_email($B)){
if(defined($A) &&($A eq '')){$A =undef;}
return ($B,$A);
}else{
return (undef,undef);
}
}else{
return (undef,undef);
}
}elsif($type eq 'HASH'){
if((ref($email_name_pair->{email}) eq '')&& (ref($email_name_pair->{name}) eq '')){
my ($A,$B)=(trim($email_name_pair->{email}),trim($email_name_pair->{name}));
if(is_email($A)){
if(defined($B) &&($B eq '')){$B =undef;}
return ($A,$B);
}else{
return (undef,undef);
}
}else{
return (undef,undef);
}
}else{
return (undef,undef)
}
}
sub gen_email_name_pair_list($$$$){
my ($email_list,$src_encoding,$dst_encoding,$dst_encoding_txt)=@_;
if(!defined($email_list)){return (undef,[]);}
if((ref $email_list eq '')||(ref $email_list eq 'HASH')){
my ($email,$name)=parse_email_name_pair($email_list);
my ($_str,$_email)=gen_email_name_pair($email,$name,$src_encoding,$dst_encoding,$dst_encoding_txt);
return ($_str,[$_email]);
}elsif(ref $email_list eq 'ARRAY'){
if(scalar(@$email_list)==2){
my ($A,$B)=(trim($email_list->[0]),trim($email_list->[1]));
#if $email_list= [$email,$email] then parse it as two email address
if(((is_email($A))&&(!is_email($B)))||((!is_email($A))&&(is_email($B)))){
my ($email,$name)=parse_email_name_pair($email_list);
my ($_str,$_email)=gen_email_name_pair($email,$name,$src_encoding,$dst_encoding,$dst_encoding_txt);
return ($_str,[$_email]);
}
}
}else{
#continue
}
if(scalar(@$email_list)==0){return (undef,[]);}
my ($str,$ra_email)=('',[]);
foreach (@$email_list) {
my ($email,$name)=parse_email_name_pair($_);
my ($_str,$_email)=gen_email_name_pair($email,$name,$src_encoding,$dst_encoding,$dst_encoding_txt);
$str.="$_str,";
push @$ra_email,$_email;
}
chop($str);
return ($str,$ra_email);
}
#===used by gen_date
my $_short_month_name=
['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
my $_short_day_name=
['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
my $_time_zone_name_2=
['-1200','-1100','-1000','-0900','-0800','-0700','-0600','-0500','-0400','-0300','-0200','-0100','+0000','+0100','+0200','+0300','+0400','+0500','+0600','+0700','+0800','+0900','+1000','+1100','+1200','+1300'];
sub gen_date(){
my @now = localtime(time);
my $sec = $now[0];
my $min = $now[1];
my $hr = $now[2];
my $day = $now[3];
my $mon = $now[4];
my $yr = $now[5] + 1900;
my $gm = Time::Local::timegm($sec,$min,$hr,$day,$mon,$yr);
my $local = Time::Local::timelocal($sec,$min,$hr,$day,$mon,$yr);
my $tz = int (($gm-$local)/3600);
my $t=[localtime(CORE::time())];
return sprintf('%03s, %02s %03s %04s %02s:%02s:%02s %05s',$_short_day_name->[$t->[6]],$t->[3],$_short_month_name->[$t->[4]],$t->[5]+1900,$t->[2],$t->[1],$t->[0],$_time_zone_name_2->[$tz+12]);
}
#=========================================
#===
sub gen_part_file($$$$$){
my ($file,$src_encoding,$dst_encoding,$dst_encoding_txt,$line_delimiter)=@_;
my $str='';
$str.="Content-Type: $file->{content_type};".$line_delimiter;
my $file_name_str;
if(defined($file->{file_name})){
$file_name_str=encode_header($file->{file_name},$src_encoding,$dst_encoding,$dst_encoding_txt);
$str.=" name=\"$file_name_str\"".$line_delimiter;
}
$str.="Content-Transfer-Encoding: base64".$line_delimiter;
if(defined($file->{content_id})){
$str.="Content-ID: <$file->{content_id}>".$line_delimiter;
}
$str.="Content-Disposition: $file->{content_disposion};".$line_delimiter;
if(defined($file->{file_name})){
$str.=" filename=\"$file_name_str\"".$line_delimiter;
}
$str.=$line_delimiter;
$str.=_my_chunk_split(MIME::Base64::encode_base64($file->{file_bin},''),$line_delimiter,72);
$str.=$line_delimiter;
return $str;
}
sub parse_part_text($$$$$$){
my ($type,$text,$src_encoding,$dst_encoding,$dst_encoding_txt,$line_delimiter)=@_;
$text=trim($text);
if(!defined($text)){$text='';}
#change encoding
$text=change_encoding($text,$src_encoding,$dst_encoding);
my $header_transfer_encoding;
if($text=~/^[\000-\177]*$/){
$header_transfer_encoding=gen_header('Content-Transfer-Encoding','7bit',$line_delimiter);
}else{
$header_transfer_encoding=gen_header('Content-Transfer-Encoding','8bit',$line_delimiter);
}
my $header_content_type;
if(($_all_ascii)&&($text=~/^[\040-\176\r\t\n]*$/)){
#all ascii
}else{
$_all_ascii=&_name_false;
}
if($type eq 'html'){
my $encoding=$_all_ascii?'us-ascii':$dst_encoding_txt;
$header_content_type=gen_header('Content-Type',"text/html; charset=$encoding;",$line_delimiter);
}elsif($type eq 'plain'){
my $encoding=$_all_ascii?'us-ascii':$dst_encoding_txt;
$header_content_type=gen_header('Content-Type',"text/plain; charset=$encoding;",$line_delimiter);
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: BUG please report it:unknow type');
}
$text=~s/\r\n/\n/g;
$text=~s/\r/\n/g;
$text=~s/\n/$line_delimiter/g;
$text.=$line_delimiter;
$text.=$line_delimiter;
return ($header_transfer_encoding,$header_content_type,$text);
}
sub sendmail($){
my ($param)=@_;
#===get sender & config
my $sender=EasyMail::Sender::get_sender($param);
my $config=EasyMail::Sender::parse_sender($sender);
my $line_delimiter=$config->{line_delimiter};
my $hide_bcc_flag =$config->{hide_bcc};
#======================
#======================
my $from_email;
my $ra_to;
my $ra_cc;
my $ra_bcc;
#======================
#===temp variable
my $str;
#======================
my $_mime_boundary= 100000;
$_all_ascii=&_name_true;
#===analyse attachment
my $mixed_files=[];
my $related_files=[];
if(defined($param->{files})){
foreach my $file(@{$param->{files}}){
my ($f,$flag)=_process_file($file);
if($flag==0){
push @$mixed_files,$f;
}elsif($flag==1){
push @$related_files,$f;
}
}
}
my $src_encoding=$param->{src_encoding};
#if all param is unicode ,may be no need to set src encoding
my $dst=$param->{dst};
if(!defined($dst)){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: dst must be set in (un,jp,cn)');
}
my ($dst_encoding,$dst_encoding_txt);
if($dst eq 'un'){
$dst_encoding='utf8';$dst_encoding_txt='utf-8';
}elsif($dst eq 'cn'){
$dst_encoding='gbk';$dst_encoding_txt='gb2312';
}elsif($dst eq 'jp'){
$dst_encoding='iso-2022-jp';$dst_encoding_txt=$dst_encoding;
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: dst must be set in (un,jp,cn)');
}
my $mail='';
#Return-Path
$mail.=gen_header('Return-Path',$param->{return_path},$line_delimiter);
my ($email,$name)=parse_email_name_pair($param->{from});
if(!defined($email)){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: must spcify from email');
}
#From
($str,$from_email)=gen_email_name_pair($email,$name,$src_encoding,$dst_encoding,$dst_encoding_txt);
$mail.=gen_header('From',$str,$line_delimiter);
if (defined($param->{mail_filter})){
if (ref $param->{mail_filter} eq 'ARRAY'){
$param->{to} = _filter_mail($param->{mail_filter}, $param->{to});
$param->{cc} = _filter_mail($param->{mail_filter}, $param->{cc});
$param->{bcc} = _filter_mail($param->{mail_filter}, $param->{bcc});
}
}
($str,$ra_to)=gen_email_name_pair_list($param->{to},$src_encoding,$dst_encoding,$dst_encoding_txt);
#To&CC
$mail.=gen_header('To',$str,$line_delimiter);
($str,$ra_cc)=gen_email_name_pair_list($param->{cc},$src_encoding,$dst_encoding,$dst_encoding_txt);
$mail.=gen_header('CC',$str,$line_delimiter);
if ((scalar(@$ra_to)==0) && (scalar(@$ra_cc)==0) ){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: to and cc must contains more than one valid email');
}
#BCC
($str,$ra_bcc)=gen_email_name_pair_list($param->{bcc},$src_encoding,$dst_encoding,$dst_encoding_txt);
if(!$hide_bcc_flag){$mail.=gen_header('BCC',$str,$line_delimiter);}
#Subject
my $subject=$param->{subject};
if(!defined($subject)){$subject='No Subject';}
$mail.=gen_header('Subject',encode_header($subject,$src_encoding,$dst_encoding,$dst_encoding_txt),$line_delimiter);
#Date
$mail.=gen_header('Date',gen_date(),$line_delimiter);
#MIME-Version
$mail.=gen_header('MIME-Version','1.0',$line_delimiter);
my $type;
if(!defined($param->{type})){
$type='plain';
}elsif($param->{type} eq 'html'){
$type='html';
}elsif(($param->{type} eq 'plain')||($param->{type} eq 'text')||($param->{type} eq 'txt')){
$type='plain';
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: please set type in (plain,html)');
}
my $text=$param->{body};
if(!defined($text)){$text='';}
my ($text_header_transfer_encoding,$text_header_content_type,$text_body)=parse_part_text($type,$text,$src_encoding,$dst_encoding,$dst_encoding_txt,$line_delimiter);
my $body;
my ($header_transfer_encoding,$header_content_type);
if(scalar(@$mixed_files)>=1){
my $mime_boundary=gen_mime_boundary($_mime_boundary++);
$header_content_type=gen_header('Content-Type','multipart/mixed;'.$line_delimiter.' boundary="'.$mime_boundary.'"',$line_delimiter);
$header_transfer_encoding='';
$body="This is a multi-part message in MIME format".$line_delimiter.$line_delimiter;
$body.="--".$mime_boundary.$line_delimiter;
if(scalar(@$related_files)>=1){
my $mime_boundary=gen_mime_boundary($_mime_boundary++);
$body.=gen_header('Content-Type','multipart/related;'.$line_delimiter.' boundary="'.$mime_boundary.'"',$line_delimiter);
$body.=$line_delimiter;
$body.="--".$mime_boundary.$line_delimiter;
$body.=$text_header_content_type;
$body.=$text_header_transfer_encoding;
$body.=$line_delimiter;
$body.=$text_body;
foreach(@$related_files){
$body.="--".$mime_boundary.$line_delimiter;
$body.=gen_part_file($_,$src_encoding,$dst_encoding,$dst_encoding_txt,$line_delimiter);
}
$body.="--".$mime_boundary."--".$line_delimiter.$line_delimiter;
}else{
$body.=$text_header_content_type;
$body.=$text_header_transfer_encoding;
$body.=$line_delimiter;
$body.=$text_body;
}
foreach(@$mixed_files){
$body.="--".$mime_boundary.$line_delimiter;
$body.=gen_part_file($_,$src_encoding,$dst_encoding,$dst_encoding_txt,$line_delimiter);
}
$body.="--".$mime_boundary."--".$line_delimiter;
}elsif(scalar(@$related_files)>=1){
my $mime_boundary=gen_mime_boundary($_mime_boundary++);
$header_content_type=gen_header('Content-Type','multipart/related;'.$line_delimiter.' boundary="'.$mime_boundary.'"',$line_delimiter);
$header_transfer_encoding='';
$body="This is a multi-part message in MIME format".$line_delimiter.$line_delimiter;
$body.="--".$mime_boundary.$line_delimiter;
$body.=$text_header_content_type;
$body.=$text_header_transfer_encoding;
$body.=$line_delimiter;
$body.=$text_body;
foreach(@$related_files){
$body.="--".$mime_boundary.$line_delimiter;
$body.=gen_part_file($_,$src_encoding,$dst_encoding,$dst_encoding_txt,$line_delimiter);
}
$body.="--".$mime_boundary."--".$line_delimiter;
}else{
$header_content_type=$text_header_content_type;
$header_transfer_encoding=$text_header_transfer_encoding;
$body.=$line_delimiter;
$body=$text_body;
}
#Content-Type
$mail.=$header_content_type;
#Transfer-Encoding
$mail.=$header_transfer_encoding;
#Other
$mail.=gen_header('X-Mailer',_name_pkg_name(),$line_delimiter);
$mail.=$line_delimiter;
#Body
$mail.=$body;
my $m=EasyMail::Sender::get_mail($sender,$mail,$from_email,$ra_to,$ra_cc,$ra_bcc);
EasyMail::Sender::sendmail($m);
}
sub _filter_mail($$){
my ($ra_filter, $email_list) = @_;
my $ra_filter_str = [];
foreach(@$ra_filter){
if (! /^([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/){
next;
}
push @$ra_filter_str, '@'.$_;
}
if((ref $email_list eq '')||(ref $email_list eq 'HASH')){
my ($email,$name)=parse_email_name_pair($email_list);
return undef if (!defined($email)); #==2.4.2==
foreach (@$ra_filter_str){
if (index($email, $_) != -1){return $email_list;}
}
return undef;
}elsif(ref $email_list eq 'ARRAY'){
if(scalar(@$email_list)==2){
my ($A,$B)=(trim($email_list->[0]),trim($email_list->[1]));
if(((is_email($A))&&(!is_email($B)))||((!is_email($A))&&(is_email($B)))){
my ($email,$name)=parse_email_name_pair($email_list);
foreach (@$ra_filter_str){
if (index($email, $_) != -1){return $email_list;}
}
return undef;
}
}elsif(scalar(@$email_list)==0){return $email_list;}
}else{
return $email_list;
}
my $filter_email_list = [];
foreach (@$email_list) {
my $remain = 0;
my ($email,$name)=parse_email_name_pair($_);
foreach (@$ra_filter_str){
if (index($email, $_) != -1){
$remain = 1;
last;
}
}
if ($remain){
push @$filter_email_list, $_;
}
}
return $filter_email_list;
}
#please use simple char in file_path and file_name
sub _process_file($){
my ($file)=@_;
my $attachment={};
if(defined($file->{file_bin})&&defined($file->{file_path})){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'_process_file: file_bin and file_path can only set one');
}elsif(defined($file->{file_path})){
my $fh=FileHandle->new($file->{file_path},'r');
if(!defined($fh)){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'_process_file: open attach file failed');
}
my $buf;
$fh->read($buf,$_max_file_len);
$fh->close();
$attachment->{file_bin}=$buf;
undef $buf;
if(defined($file->{file_name})){
$attachment->{file_name}=trim($file->{file_name});
}else{
$attachment->{file_name}=File::Basename::basename(trim($file->{file_path}));
}
}elsif(defined($file->{file_bin})){
$attachment->{file_bin}=$file->{file_bin};
$attachment->{file_name}=trim($file->{file_name});
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'_process_file: file_bin and file_path must set one');
}
#===if u don't set file_name please set content_type
if(defined($file->{content_type})){
$attachment->{content_type}=$file->{content_type};
}elsif(defined($attachment->{file_name})){
$attachment->{content_type}=guess_file_content_type($attachment->{file_name});
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'_process_file: if u don\'t set file_name please set content_type');
}
if(defined($file->{content_id})){
$attachment->{content_id}=$file->{content_id};
$attachment->{content_disposion}='inline';
delete $attachment->{file_name};
}else{
$attachment->{content_disposion}='attachment';
#===attachment must have a file name
if(!defined($attachment->{file_name})){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'_process_file: please set file_name');
}
}
return ($attachment,$attachment->{content_id}?1:0);
}
1;
package EasyMail::Sender;
use strict;
use warnings(FATAL=>'all');
sub foo{1};
sub _name_pkg_name{'EasyMail::Sender'}
sub _name_true{1;}
sub _name_false{'';}
#mail option
#SENDMAIL
# sendmail_path
# sendmail_use_close
# sendmail_mail
#SMTPAUTHLOGIN | SMTPAUTHPLAIN | SMTPAUTHNONE
# smtp_host
# smtp_port
# print_msg
# smtp_mail
# from
# ra_to
# ra_cc
# ra_bcc
# smtp_usr (SMTPAUTHLOGIN | SMTPAUTHPLAIN)
# smtp_pass(SMTPAUTHLOGIN | SMTPAUTHPLAIN)
#
#DIRECT
#
sub sendmail($){
my $param_count=scalar(@_);
if($param_count==1){
if($_[0]->{type} eq 'SMTPAUTHLOGIN'){
_smtp_AUTH_LOGIN($_[0]);
}elsif($_[0]->{type} eq 'SMTPAUTHPLAIN'){
_smtp_AUTH_PLAIN($_[0]);
}elsif($_[0]->{type} eq 'SMTPAUTHNONE'){
_smtp_AUTH_NONE($_[0]);
}elsif($_[0]->{type} eq 'SENDMAIL'){
_sendmail($_[0]);
}elsif($_[0]->{type} eq 'DIRECT'){
_direct_send($_[0]);
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: unknow sender type ');
}
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: param count should be 1');
}
}
sub get_sender($){
my $param_count=scalar(@_);
if($param_count==1){
my $sender={};
my $type=$_[0]->{sender_type};
if(!defined($type)){$type='SENDMAIL';}
if($type eq 'SENDMAIL'){
$sender->{type}='SENDMAIL';
$sender->{sendmail_path}=defined($_[0]->{sendmail_path})?$_[0]->{sendmail_path}:'sendmail';
$sender->{sendmail_use_close}=((!defined($_[0]->{sendmail_use_close}))||($_[0]->{sendmail_use_close}))?&_name_true:&_name_false;
return $sender;
}elsif($type eq 'SMTPAUTHLOGIN'){
$sender->{type}='SMTPAUTHLOGIN';
$sender->{smtp_host}=defined($_[0]->{smtp_host})?$_[0]->{smtp_host}:'127.0.0.1';
$sender->{smtp_port}=defined($_[0]->{smtp_port})?$_[0]->{smtp_port}:25;
$sender->{print_msg}=(defined($_[0]->{print_msg})&&$_[0]->{print_msg})?&_name_true:&_name_false;
$sender->{smtp_usr}=$_[0]->{smtp_usr};
if(!defined($sender->{smtp_usr})){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: smtp_usr must set');
}
$sender->{smtp_pass}=$_[0]->{smtp_pass};
if(!defined($sender->{smtp_pass})){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: smtp_pass must set');
}
return $sender;
}elsif($type eq 'SMTPAUTHPLAIN'){
$sender->{type}='SMTPAUTHPLAIN';
$sender->{smtp_host}=defined($_[0]->{smtp_host})?$_[0]->{smtp_host}:'127.0.0.1';
$sender->{smtp_port}=defined($_[0]->{smtp_port})?$_[0]->{smtp_port}:25;
$sender->{print_msg}=(defined($_[0]->{print_msg})&&$_[0]->{print_msg})?&_name_true:&_name_false;
$sender->{smtp_usr}=$_[0]->{smtp_usr};
if(!defined($sender->{smtp_usr})){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: smtp_usr must set');
}
$sender->{smtp_pass}=$_[0]->{smtp_pass};
if(!defined($sender->{smtp_pass})){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: smtp_pass must set');
}
return $sender;
}elsif($type eq 'SMTPAUTHNONE'){
$sender->{type}='SMTPAUTHNONE';
$sender->{smtp_host}=defined($_[0]->{smtp_host})?$_[0]->{smtp_host}:'127.0.0.1';
$sender->{smtp_port}=defined($_[0]->{smtp_port})?$_[0]->{smtp_port}:25;
$sender->{print_msg}=(defined($_[0]->{print_msg})&&$_[0]->{print_msg})?&_name_true:&_name_false;
return $sender;
}elsif($type eq 'DIRECT'){
$sender->{type}='DIRECT';
#$sender->{smtp_host}=defined($_[0]->{smtp_host})?$_[0]->{smtp_host}:'127.0.0.1';
#$sender->{smtp_port}=defined($_[0]->{smtp_port})?$_[0]->{smtp_port}:25;
$sender->{print_msg}=(defined($_[0]->{print_msg})&&$_[0]->{print_msg})?&_name_true:&_name_false;
return $sender;
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: unknow sender type');
}
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: param count should be 1');
}
}
sub get_mail($$$$$$){
my $param_count=scalar(@_);
if($param_count==6){
my $type=$_[0]->{type};
if($type eq 'SENDMAIL'){
$_[0]->{sendmail_mail}=$_[1];
return $_[0];
}elsif($type eq 'SMTPAUTHLOGIN'){
$_[0]->{smtp_mail}=$_[1];
$_[0]->{from}=$_[2];
$_[0]->{ra_to}=$_[3];
$_[0]->{ra_cc}=$_[4];
$_[0]->{ra_bcc}=$_[5];
return $_[0];
}elsif($type eq 'SMTPAUTHPLAIN'){
$_[0]->{smtp_mail}=$_[1];
$_[0]->{from}=$_[2];
$_[0]->{ra_to}=$_[3];
$_[0]->{ra_cc}=$_[4];
$_[0]->{ra_bcc}=$_[5];
return $_[0];
}elsif($type eq 'SMTPAUTHNONE'){
$_[0]->{smtp_mail}=$_[1];
$_[0]->{from}=$_[2];
$_[0]->{ra_to}=$_[3];
$_[0]->{ra_cc}=$_[4];
$_[0]->{ra_bcc}=$_[5];
return $_[0];
}elsif($type eq 'DIRECT'){
$_[0]->{smtp_mail}=$_[1];
$_[0]->{from}=$_[2];
$_[0]->{ra_to}=$_[3];
$_[0]->{ra_cc}=$_[4];
$_[0]->{ra_bcc}=$_[5];
return $_[0];
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: unknow sender type');
}
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: param count should be 6');
}
}
sub parse_sender($){
my $type=$_[0]->{type};
if(!defined($type)){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: unknow sender type');
}elsif($type eq 'SENDMAIL'){
return {line_delimiter=>"\n",hide_bcc=>&_name_false};
}elsif(($type eq 'SMTPAUTHLOGIN')||($type eq 'SMTPAUTHPLAIN')||($type eq 'SMTPAUTHNONE')||($type eq 'DIRECT') ){
return {line_delimiter=>"\r\n",hide_bcc=>&_name_true};
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: unknow sender type');
}
}
sub _direct_send {
my ($mail) = @_;
my $email = $mail->{'ra_to'}->[0];
if ($email =~ /^[a-zA-Z0-9\_\.\-]+\@((?:[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6})$/){
my $address = lc($1);
require Net::DNS;
my @mx = Net::DNS::mx($address);
if (scalar(@mx)==0){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: cannot parse mx record!');
} else {
$mail->{'ra_to'} = [$email];
$mail->{'sender_type'} = 'SMTPAUTHNONE';
$mail->{'smtp_host'} = $mx[0]->exchange;
$mail->{smtp_port}=25;
_smtp_AUTH_NONE($mail);
return;
}
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: BUG!');
}
}
sub _smtp_AUTH_LOGIN($){
my ($mail)=@_;
my $smtp_host=defined($mail->{smtp_host})?$mail->{smtp_host}:'localhost';
my $smtp_port=defined($mail->{smtp_port})?$mail->{smtp_port}:25;
my $print_msg=defined($mail->{print_msg})?$mail->{print_msg}:0;
my $sock=new IO::Socket::INET->new(PeerPort=>$smtp_port,Proto=>'tcp',PeerAddr=>$smtp_host);
if(!defined($sock)){CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: cannot connect to smtp server!');}
_server_parse($sock, "220",$print_msg,__LINE__);
_server_send($sock,"EHLO $mail->{smtp_host}\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
_server_send($sock,"AUTH LOGIN\r\n",$print_msg,__LINE__);
_server_parse($sock, "334",$print_msg,__LINE__);
_server_send($sock,MIME::Base64::encode_base64($mail->{smtp_usr},'')."\r\n",$print_msg,__LINE__);
_server_parse($sock, "334",$print_msg,__LINE__);
_server_send($sock,MIME::Base64::encode_base64($mail->{smtp_pass},'')."\r\n",$print_msg,__LINE__);
_server_parse($sock, "235",$print_msg,__LINE__);
_server_send($sock,"MAIL FROM: <$mail->{from}>\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
foreach my $to(@{$mail->{ra_to}}){
_server_send($sock,"RCPT TO: <$to>\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
}
foreach my $cc(@{$mail->{ra_cc}}){
_server_send($sock,"RCPT TO: <$cc>\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
}
foreach my $bcc(@{$mail->{ra_bcc}}){
_server_send($sock,"RCPT TO: <$bcc>\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
}
_server_send($sock,"DATA\r\n",$print_msg,__LINE__);
_server_parse($sock, "354",$print_msg,__LINE__);
_server_send($sock,$mail->{smtp_mail}."\r\n.\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
_server_send($sock,"QUIT\r\n",$print_msg,__LINE__);
_server_parse($sock, "221",$print_msg,__LINE__);
$sock->shutdown(2);
}
sub _smtp_AUTH_PLAIN($){
my ($mail)=@_;
my $smtp_host=defined($mail->{smtp_host})?$mail->{smtp_host}:'localhost';
my $smtp_port=defined($mail->{smtp_port})?$mail->{smtp_port}:25;
my $print_msg=defined($mail->{print_msg})?$mail->{print_msg}:0;
my $sock=new IO::Socket::INET->new(PeerPort=>$smtp_port,Proto=>'tcp',PeerAddr=>$smtp_host);
if(!defined($sock)){CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: cannot connect to smtp server!');}
_server_parse($sock, "220",$print_msg,__LINE__);
_server_send($sock,"EHLO $mail->{smtp_host}\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
_server_send($sock,"AUTH PLAIN ".MIME::Base64::encode_base64(join("\0",$mail->{smtp_usr},$mail->{smtp_pass})),$print_msg,__LINE__);
_server_parse($sock, "235",$print_msg,__LINE__);
_server_send($sock,"MAIL FROM: <$mail->{from}>\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
foreach my $to(@{$mail->{ra_to}}){
_server_send($sock,"RCPT TO: <$to>\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
}
foreach my $cc(@{$mail->{ra_cc}}){
_server_send($sock,"RCPT TO: <$cc>\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
}
foreach my $bcc(@{$mail->{ra_bcc}}){
_server_send($sock,"RCPT TO: <$bcc>\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
}
_server_send($sock,"DATA\r\n",$print_msg,__LINE__);
_server_parse($sock, "354",$print_msg,__LINE__);
_server_send($sock,$mail->{smtp_mail}."\r\n.\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
_server_send($sock,"QUIT\r\n",$print_msg,__LINE__);
_server_parse($sock, "221",$print_msg,__LINE__);
$sock->shutdown(2);
}
sub _smtp_AUTH_NONE($){
my ($mail)=@_;
my $smtp_host=defined($mail->{smtp_host})?$mail->{smtp_host}:'localhost';
my $smtp_port=defined($mail->{smtp_port})?$mail->{smtp_port}:25;
my $print_msg=defined($mail->{print_msg})?$mail->{print_msg}:0;
my $sock=new IO::Socket::INET->new(PeerPort=>$smtp_port,Proto=>'tcp',PeerAddr=>$smtp_host);
if(!defined($sock)){CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: cannot connect to smtp server!');}
_server_parse($sock, "220",$print_msg,__LINE__);
_server_send($sock,"EHLO $mail->{smtp_host}\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
_server_send($sock,"MAIL FROM: <$mail->{from}>\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
foreach my $to(@{$mail->{ra_to}}){
_server_send($sock,"RCPT TO: <$to>\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
}
foreach my $cc(@{$mail->{ra_cc}}){
_server_send($sock,"RCPT TO: <$cc>\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
}
foreach my $bcc(@{$mail->{ra_bcc}}){
_server_send($sock,"RCPT TO: <$bcc>\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
}
_server_send($sock,"DATA\r\n",$print_msg,__LINE__);
_server_parse($sock, "354",$print_msg,__LINE__);
_server_send($sock,$mail->{smtp_mail}."\r\n.\r\n",$print_msg,__LINE__);
_server_parse($sock, "250",$print_msg,__LINE__);
_server_send($sock,"QUIT\r\n",$print_msg,__LINE__);
_server_parse($sock, "221",$print_msg,__LINE__);
$sock->shutdown(2);
}
sub _sendmail($){
my ($mail,$path,$use_close)=($_[0]->{sendmail_mail},$_[0]->{sendmail_path},$_[0]->{sendmail_use_close});
$path=defined($path)?$path:'sendmail';
eval{
if(!open(MAIL, "| $path -t")){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: sendmail_path not valid');
}
};
if($@){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: sendmail_path not valid');
}
print MAIL $mail;
undef $mail;
unless(defined($use_close)&&$use_close==0){close(MAIL);}
}
sub _server_parse($$$$){
my ($socket, $response,$print_msg,$line)=@_;
my $server_response;
$socket->recv($server_response, 4096);
if(!defined($server_response)){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: couldn\'t get mail server response codes');
}
my @response_lines=split(/\015?\012/, $server_response, -1);
my $code;
while(1){
my $response_line=shift @response_lines;
if(!defined($response_line)){last;}
if($print_msg){print $response_line."\n";}
if($response_line=~ s/^(\d\d\d)(.?)//o){if($2 ne "-"){$code=$1;last;}}
}
#qian.yu
if (!(defined($code) && defined($response) && ($code eq $response) )){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'')."sendmail: couldn\'t get expected mail server response codes \nExpected: $response ,\n Server Response:\n $server_response ");
}
};
sub _server_send($$$){
my ($socket,$msg,$print_msg,$line)=@_;
if($print_msg){
print trim($msg)."\n";
}
if(!$socket->send($msg)){
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: send command to server error');
};
}
sub trim($) {
my $param_count=scalar(@_);
if($param_count==1){
local $_=$_[0];
unless(defined($_)){return undef;}
s/^\s+//,s/\s+$//;
return $_ ;
}else{
CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'trim: param count should be 1');
}
}
1;
__END__
=head1 NAME
EasyMail - Perl Send Mail Interface
=head1 SYNOPSIS
use EasyMail;
if(defined(&EasyMail::foo)){
print "lib is included";
}else{
print "lib is not included";
}
my $email_from = {'email'=>'test@adways.net', 'name'=>'Test'};
my $email_to = 'receiver@adways.net';
# $email_name_pair is a variable specify a email and name
# $name can be undef,set $name=undef if $name eq ''
# $email_name_pair can be a string
# A: "$email"
# B: "$name $email" if not A
# C: "$email $name" if not A,B
# D: "\"$name\"<$email>" if not A,B,C
# E: "$name<$email>" if not A,B,C,D
# $email can be a array_ref
# A: [$email,$name]
# B: [$name,$email] if not A
# $email can be a hash_ref
# {email=>$email,name=>$name}
my $email_cc = $email_to;
my $email_bcc = [];
my $ra_filters = ['adways.net'];
my $file = {
'file_path' => '/usr/local/src/test.txt',
#path to file
'file_bin' => undef,
#binary content of file
'file_name' => undef,
#file name
'content_type' => undef,
#content type
'content_id' => undef
#content_id, when u wanna embed picture in html email u need it
# the rule of $file
# 1,you "must and can only" set one of file_path and file_bin,or will throw an exception
# 2,if file_name set, {file_name}=file_name
# 3,if file_name not set and file_path set,then {file_name} will be generate by file_path
# 4,if file_name not set and file_path not set and content_id set,then no {file_name}
# 5,if content_type set,then {content_type}=content_type
# 6,if content_type not set and {file_name} set,then {content_type} will be generate by {file_name}
# 7,if content_id set,then consider this file as part of multi_related structure,else if content_id not set then consider this file as part of multi_mixed structure
};
my $mail = {
'sender_type' => 'SMTPAUTHLOGIN',
# SENDMAIL | SMTPAUTHLOGIN | SMTPAUTHPLAIN | SMTPAUTHNONE
# default is 'SENDMAIL'
'smtp_host' => '127.0.0.1',
# smtp host address default is 127.0.0.1 (if sender is smtp)
'smtp_port' => 25,
# smtp host port (if sender is smtp)
'smtp_usr' => 'admin',
# smtp author usr name (if needed)
'smtp_pass' => 'password',
# smtp author usr pass (if needed)
'sendmail_path' => '/usr/sbin',
# the path of sendmail, default is 'sendmail'(if needed)
'type' => 'txt',
# can be 'html' 'plain' 'txt' 'text' default is 'plain'
# 'txt' 'text' is alias for 'plain'
# the recomend way you set mail as plain text mail is set it 'plain'
'subject' => 'Test Mail',
# the mail subject, default is 'No Subject'
'body' => 'This is a test.',
# the text content of mail, default is ''
'files' => $file,
# files to be attach to the mail files=>[$file,$file,..], default is []
'from' => $email_from,
# $email_name_pair
'to' => $email_to,
# $email_name_pair || [$email_name_pair,$email_name_pair,..], default is []
'cc' => $email_cc,
# $email_name_pair || [$email_name_pair,$email_name_pair,..], default is []
'bcc' => $email_bcc,
# $email_name_pair || [$email_name_pair,$email_name_pair,..], default is []
'mail_filter' => $ra_filters,
# [$email_filter, $email_filter, ..], default is []
# email_filter: only allow specified email to send ( for debug use)
'return_path' => '/tmp/failmail',
#sendmail to this address if sendmail fail ,default is not set
'src_encoding' => 'utf8',
#source mail encoding
'dst' => 'un'
# 'cn' || 'un' || 'jp'
# 'cn' for gb2312 encoding, 'un' for utf8 encoding, 'jp' for iso-2022-jp encoding
# extra rules:
# from is must set
# to and cc must contains more than one valid email
# if (input is all unicode or input is all ascii){
# src_encoding can be not set
# }else{
# src_encoding must set
# }
# dst must set
# in to cc bcc, [$email,$email] is parse as two receiver email
};
EasyMail::sendmail($mail);
I<The synopsis above only lists the major methods and parameters.>
=head1 Basic Variables and Hash Options
=head2 $mail - all content of the mail
$mail is a hash_ref with below options :
sender_type
# SENDMAIL | SMTPAUTHLOGIN | SMTPAUTHPLAIN | SMTPAUTHNONE | DIRECT
# default is 'SENDMAIL'
smtp_host
# smtp host address default is 127.0.0.1 (if sender is smtp)
smtp_port
# smtp host address (if sender is smtp)
smtp_usr
# smtp author usr name (if needed)
smtp_pass
# smtp author usr pass (if needed)
sendmail_path
#the path of sendmail, default is 'sendmail'(if needed)
type
#can be 'html' 'plain' 'txt' 'text' default is 'plain'
#'txt' 'text' is alias for 'plain'
#the recomend way you set mail as plain text mail is set it 'plain'
subject
#the mail subject, default is 'No Subject'
body
#the text content of mail, default is ''
files
#files to be attach to the mail files=>[$file,$file,..], default is []
from
#$email_name_pair
to
# $email_name_pair || [$email_name_pair,$email_name_pair,..], default is []
cc
# $email_name_pair || [$email_name_pair,$email_name_pair,..], default is []
bcc
# $email_name_pair || [$email_name_pair,$email_name_pair,..], default is []
return_path
#sendmail to this address if sendmail fail ,default is not set
src_encoding
#source mail encoding
dst
# 'cn' || 'un' || 'jp'
# 'cn' for gb2312 encoding, 'un' for utf8 encoding, 'jp' for iso-2022-jp encoding
extra rules:
from is must set
to and cc must contains more than one valid email
if (input is all unicode or input is all ascii){
src_encoding can be not set
}else{
src_encoding must set
}
dst must set
in to cc bcc, [$email,$email] is parse as two receiver email
=head2 $email_name_pair - the email-name pair
$email_name_pair is a variable specify a email and name
$name can be undef,set $name=undef if $name eq ''
$email_name_pair can be a string:
A: "$email"
B: "$name $email" if not A
C: "$email $name" if not A,B
D: "\"$name\"<$email>" if not A,B,C
E: "$name<$email>" if not A,B,C,D
$email can be a array_ref:
A: [$email,$name]
B: [$name,$email] if not A
$email can be a hash_ref:
{email=>$email,name=>$name}
=head2 $file - the file attached
$file is a hash_ref with below options :
file_path
#path to file
file_bin
#binary content of file
file_name
#file name
content_type
#content type
content_id
#content_id, when u wanna embed picture in html email u need it
the rule of $file:
1,you "must and can only" set one of file_path and file_bin,or will throw an exception
2,if file_name set, {file_name}=file_name
3,if file_name not set and file_path set,then {file_name} will be generate by file_path
4,if file_name not set and file_path not set and content_id set,then no {file_name}
5,if content_type set,then {content_type}=content_type
6,if content_type not set and {file_name} set,then {content_type} will be generate by {file_name}
7,if content_id set,then consider this file as part of multi_related structure,else if content_id not set then consider this file as part of multi_mixed structure
=head1 COPYRIGHT
The EasyMail module is Copyright (c) 2003-2008 QIAN YU.
All rights reserved.
You may distribute under the terms of either the GNU General Public
License or the Artistic License, as specified in the Perl README file.