File Coverage

blib/lib/EasyMail.pm
Criterion Covered Total %
statement 31 651 4.7
branch 0 398 0.0
condition 0 105 0.0
subroutine 11 48 22.9
pod 0 15 0.0
total 42 1217 3.4


line stmt bran cond sub pod time code
1             package EasyMail;
2 1     1   21207 use strict;
  1         2  
  1         44  
3 1     1   5 use warnings(FATAL=>'all');
  1         2  
  1         82  
4            
5             our $VERSION = '2.5.2';
6            
7             #===================================
8             #===Module : 43f01b295f6fcfca
9             #===Version : 43f01b600bc33f65
10             #===================================
11            
12             #===================================
13             #===Module : Framework::EasyMail
14             #===File : lib/Framework/EasyMail.pm
15             #===Comment : a lib to send email
16             #===Require : File::Basename MIME::Base64 FileHandle IO::Socket::INET Time::Local Encode
17             #===================================
18            
19             #===================================
20             #===Author : qian.yu ===
21             #===Email : foolfish@cpan.org ===
22             #===MSN : qian.yu@adways.net ===
23             #===QQ : 9097939 ===
24             #===Homepage: www.fishlib.cn ===
25             #===================================
26            
27             #=======================================
28             #===Author : huang.shuai ===
29             #===Email : huang.shuai@adways.net ===
30             #===MSN : huang.shuai@adways.net ===
31             #=======================================
32            
33             #BUG
34             # * Return-Path is not function in sendmail daemon(not qmail daemon), for further help contact author
35            
36             #Future Request:
37            
38             #===2.5.2(2008-12-08): fix bug "http://rt.cpan.org/Ticket/Display.html?id=34032",thanks to "Ursetti, Jerry" find this bug
39             #===2.5.1(2008-07-16): fix bug when traslate charset from utf8 to iso-2022-jp
40             # (2008-05-08): fix bug on dst = 'un'
41             #===2.5.0(2008-03-12): add DIRECT send type,if you use DIRECT module "Net::DNS" is required
42             #===2.4.4(2007-10-10): modify X-Mailer, remove Thread-Index and X-MimeOLE, fix BCC bug
43             #===2.4.3(2006-08-28): fix parse mail list bugs
44             #===2.4.2(2006-08-17): fix filter bugs
45             #===2.4.1(2006-08-01): add email filter
46             #===2.4.0(2006-07-31): document format
47             #===2.3.0(2005-08-18): smtp support, non-ascii attachment file name support
48             #===2.0.1(2005-08-12): modified _sendmail, die if sendmail_path not valid
49             #===2.0.0(2005-08-12): second version release, Simplify the first version, and add some function
50            
51 1     1   6 use File::Basename;
  1         7  
  1         126  
52 1     1   952 use MIME::Base64;
  1         771  
  1         61  
53 1     1   3430 use FileHandle;
  1         42638  
  1         7  
54 1     1   28746 use IO::Socket::INET;
  1         47792  
  1         12  
55 1     1   742 use Time::Local;
  1         2  
  1         72  
56 1     1   1032 use Encode;
  1         35356  
  1         6128  
57            
58 0     0 0 0 sub foo{1};
59 0     0   0 sub _name_pkg_name{'EasyMail'}
60 1     1   3 sub _name_true{1;}
61 0     0     sub _name_false{'';}
62            
63             my $_max_file_len = 100000000;
64            
65             my $_all_ascii=&_name_true;
66            
67             #===$str=trim($str)
68             #===delete blank before and after $str, return undef if $str is undef
69             sub trim($) {
70 0     0 0   my $param_count=scalar(@_);
71 0 0         if($param_count==1){
72 0           local $_=$_[0];
73 0 0         unless(defined($_)){return undef;}
  0            
74 0           s/^\s+//,s/\s+$//;
75 0           return $_ ;
76             }else{
77 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'trim: param count should be 1');
78             }
79             }
80            
81             #===$flag=is_email($id)
82             #===check whether a valid email address
83             sub is_email($){
84 0     0 0   my $param_count=scalar(@_);
85 0 0         if($param_count==1){
86 0           local $_=$_[0];
87 0 0         if(!defined($_)){
    0          
88 0 0         return defined(&_name_false)?&_name_false:'';
89             }elsif(/^[a-zA-Z0-9\_\.\-]+\@([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/){
90 0 0         return defined(&_name_true)?&_name_true:1;
91             }else{
92 0 0         return defined(&_name_false)?&_name_false:'';
93             }
94             }else{
95 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'is_email: param count should be 1');
96             }
97             }
98            
99             #===generate a unique mime_boundary string
100             sub gen_mime_boundary($){
101 0     0 0   '------------06010007000403080202'.(shift);
102             }
103            
104             #===guess file content type from it's name
105             sub guess_file_content_type($){
106 0     0 0   my($filename)=@_;
107 0 0         if(!defined($filename)){return undef;}
  0            
108 0           my $map={
109             'au' => 'audio/basic',
110             'avi' => 'video/x-msvideo',
111             'class' => 'application/octet-stream',
112             'cpt' => 'application/mac-compactpro',
113             'dcr' => 'application/x-director',
114             'dir' => 'application/x-director',
115             'doc' => 'application/msword',
116             'exe' => 'application/octet-stream',
117             'gif' => 'image/gif',
118             'gtx' => 'application/x-gentrix',
119             'jpeg' => 'image/jpeg',
120             'jpg' => 'image/jpeg',
121             'js' => 'application/x-javascript',
122             'hqx' => 'application/mac-binhex40',
123             'htm' => 'text/html',
124             'html' => 'text/html',
125             'mid' => 'audio/midi',
126             'midi' => 'audio/midi',
127             'mov' => 'video/quicktime',
128             'mp2' => 'audio/mpeg',
129             'mp3' => 'audio/mpeg',
130             'mpeg' => 'video/mpeg',
131             'mpg' => 'video/mpeg',
132             'pdf' => 'application/pdf',
133             'pm' => 'text/plain',
134             'pl' => 'text/plain',
135             'ppt' => 'application/powerpoint',
136             'ps' => 'application/postscript',
137             'qt' => 'video/quicktime',
138             'ram' => 'audio/x-pn-realaudio',
139             'rtf' => 'application/rtf',
140             'tar' => 'application/x-tar',
141             'tif' => 'image/tiff',
142             'tiff' => 'image/tiff',
143             'txt' => 'text/plain',
144             'wav' => 'audio/x-wav',
145             'xbm' => 'image/x-xbitmap',
146             'zip' => 'application/zip'
147             };
148 0           my ($base,$path,$type) = File::Basename::fileparse($filename,qr{\..*});
149 0 0         if($type){$type=lc(substr($type,1))};
  0            
150 0 0         $map->{$type} or 'application/octet-stream';
151             }
152            
153             #===use base64 to encode header
154             sub _encode_b($$){
155 0     0     my($str,$encoding)=@_;
156 0           '=?'.$encoding.'?B?'.MIME::Base64::encode_base64($str,'').'?=';
157             }
158            
159             #===cut the str into specified length
160             sub _my_chunk_split($$$){
161 0     0     my ($str,$line_delimiter,$line_len)=@_;
162 0           my $len=length($str);
163 0           my $out='';
164 0           while ($len>0){
165 0 0         if ($len>=$line_len){
166 0           $out.=substr($str,0,$line_len).$line_delimiter;
167 0           $str=substr($str,$line_len);
168 0           $len=$len-$line_len;
169             }else{
170 0           $out.=$str.$line_delimiter;
171 0           $str='';
172 0           $len=0;
173             }
174             }
175 0           $out;
176             }
177            
178             sub change_encoding($$$){
179 0 0 0 0 0   if(defined(&utf8::is_utf8)&&utf8::is_utf8($_[0])){
    0 0        
    0 0        
    0 0        
      0        
180 0           return Encode::encode($_[2],$_[0]);
181             }elsif($_[0]=~/^[\040-\176\r\t\n]*$/){
182             #no need to do anything if all ascii
183 0           return $_[0];
184             }elsif(defined($_[1])&&defined($_[2])&&($_[1] eq $_[2])){
185             #no need to do anything if $src_encoding=$dst_encoding
186 0           return $_[0];
187             }elsif(defined($_[1])&&defined($_[2])&&($_[1] ne $_[2])){
188 0 0 0       if ($_[1] eq 'utf8' and $_[2] eq 'iso-2022-jp') {
189 0           eval {
190 0           require Unicode::Japanese;
191             };
192 0 0         if ($@) {
193 0           return Encode::encode($_[2],Encode::decode($_[1],$_[0]));
194             } else {
195 0           return Unicode::Japanese->new($_[0])->jis;
196             }
197             } else {
198 0           return Encode::encode($_[2],Encode::decode($_[1],$_[0]));
199             }
200             }else{
201 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: you must set src_encoding');
202             }
203             }
204            
205             #===encoder header
206             sub encode_header($$$$){
207 0     0 0   my ($str,$src_encoding,$dst_encoding,$dst_encoding_txt)=@_;
208             #change encoding
209 0           $str=change_encoding($str,$src_encoding,$dst_encoding);
210 0 0         if($str=~/^[\040-\176]*$/){
211             #if all ascii, no need to encode
212             }else{
213 0           $str=_encode_b($str,$dst_encoding_txt);
214 0           $_all_ascii=&_name_false;
215             }
216 0           $str;
217             }
218            
219             #===gen header
220             sub gen_header($$$){
221 0     0 0   my ($key,$value,$line_delimiter)=@_;
222 0 0         return defined($value)?$key.': '.$value.$line_delimiter:'';
223             }
224            
225             #===gen "Bill Gates"
226             sub gen_email_name_pair($$$$$){
227 0     0 0   my ($email,$name,$src_encoding,$dst_encoding,$dst_encoding_txt)=@_;
228 0 0         if(!is_email($email)){
229 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: not a valid email address');
230             }
231             #if no from_name ,just return it
232 0 0         if(!defined($name)){return ($email,$email);}
  0            
233             #change encoding
234 0           $name=encode_header($name,$src_encoding,$dst_encoding,$dst_encoding_txt);
235 0           $name=~s/([\\\"])/\\$1/g;
236 0           return ("\"$name\" <$email>",$email);
237             }
238            
239             sub parse_email_name_pair($){
240 0     0 0   my ($email_name_pair)=@_;
241 0           my ($email,$name);
242 0           my $type=ref $email_name_pair;
243 0 0 0       if(($type eq '')&&(defined($email_name_pair))){
    0          
    0          
244 0           local $_=$email_name_pair;
245 0           s/^\s+//,s/\s+$//;
246 0 0         if(/^[a-zA-Z0-9\_\.\-]+\@([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/){
    0          
    0          
    0          
    0          
247 0           return ($_,undef);
248             }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})$/){
249 0           return ($3,$1);
250             }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])?)$/){
251 0           return ($1,$4);
252             }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]*[\>]$/){
253 0           return ($2,$1);
254             }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]*[\>]$/){
255 0           return ($3,$1);
256             }else{
257 0           return (undef,undef);
258             }
259             }elsif($type eq 'ARRAY'){
260 0 0 0       if((ref($email_name_pair->[0]) eq '')&& (ref($email_name_pair->[1]) eq '')){
261 0           my ($A,$B)=(trim($email_name_pair->[0]),trim($email_name_pair->[1]));
262 0 0         if(is_email($A)){
    0          
263 0 0 0       if(defined($B) &&($B eq '')){$B =undef;}
  0            
264 0           return ($A,$B);
265             }elsif(is_email($B)){
266 0 0 0       if(defined($A) &&($A eq '')){$A =undef;}
  0            
267 0           return ($B,$A);
268             }else{
269 0           return (undef,undef);
270             }
271             }else{
272 0           return (undef,undef);
273             }
274             }elsif($type eq 'HASH'){
275 0 0 0       if((ref($email_name_pair->{email}) eq '')&& (ref($email_name_pair->{name}) eq '')){
276 0           my ($A,$B)=(trim($email_name_pair->{email}),trim($email_name_pair->{name}));
277 0 0         if(is_email($A)){
278 0 0 0       if(defined($B) &&($B eq '')){$B =undef;}
  0            
279 0           return ($A,$B);
280             }else{
281 0           return (undef,undef);
282             }
283             }else{
284 0           return (undef,undef);
285             }
286             }else{
287             return (undef,undef)
288 0           }
289             }
290            
291             sub gen_email_name_pair_list($$$$){
292 0     0 0   my ($email_list,$src_encoding,$dst_encoding,$dst_encoding_txt)=@_;
293 0 0         if(!defined($email_list)){return (undef,[]);}
  0            
294 0 0 0       if((ref $email_list eq '')||(ref $email_list eq 'HASH')){
    0          
295 0           my ($email,$name)=parse_email_name_pair($email_list);
296 0           my ($_str,$_email)=gen_email_name_pair($email,$name,$src_encoding,$dst_encoding,$dst_encoding_txt);
297 0           return ($_str,[$_email]);
298             }elsif(ref $email_list eq 'ARRAY'){
299 0 0         if(scalar(@$email_list)==2){
300 0           my ($A,$B)=(trim($email_list->[0]),trim($email_list->[1]));
301             #if $email_list= [$email,$email] then parse it as two email address
302 0 0 0       if(((is_email($A))&&(!is_email($B)))||((!is_email($A))&&(is_email($B)))){
      0        
      0        
303 0           my ($email,$name)=parse_email_name_pair($email_list);
304 0           my ($_str,$_email)=gen_email_name_pair($email,$name,$src_encoding,$dst_encoding,$dst_encoding_txt);
305 0           return ($_str,[$_email]);
306             }
307             }
308             }else{
309             #continue
310             }
311 0 0         if(scalar(@$email_list)==0){return (undef,[]);}
  0            
312 0           my ($str,$ra_email)=('',[]);
313 0           foreach (@$email_list) {
314 0           my ($email,$name)=parse_email_name_pair($_);
315 0           my ($_str,$_email)=gen_email_name_pair($email,$name,$src_encoding,$dst_encoding,$dst_encoding_txt);
316 0           $str.="$_str,";
317 0           push @$ra_email,$_email;
318             }
319 0           chop($str);
320 0           return ($str,$ra_email);
321             }
322            
323             #===used by gen_date
324             my $_short_month_name=
325             ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
326             my $_short_day_name=
327             ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
328             my $_time_zone_name_2=
329             ['-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'];
330             sub gen_date(){
331 0     0 0   my @now = localtime(time);
332 0           my $sec = $now[0];
333 0           my $min = $now[1];
334 0           my $hr = $now[2];
335 0           my $day = $now[3];
336 0           my $mon = $now[4];
337 0           my $yr = $now[5] + 1900;
338 0           my $gm = Time::Local::timegm($sec,$min,$hr,$day,$mon,$yr);
339 0           my $local = Time::Local::timelocal($sec,$min,$hr,$day,$mon,$yr);
340 0           my $tz = int (($gm-$local)/3600);
341 0           my $t=[localtime(CORE::time())];
342 0           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]);
343             }
344            
345             #=========================================
346            
347             #===
348             sub gen_part_file($$$$$){
349 0     0 0   my ($file,$src_encoding,$dst_encoding,$dst_encoding_txt,$line_delimiter)=@_;
350 0           my $str='';
351            
352 0           $str.="Content-Type: $file->{content_type};".$line_delimiter;
353 0           my $file_name_str;
354 0 0         if(defined($file->{file_name})){
355 0           $file_name_str=encode_header($file->{file_name},$src_encoding,$dst_encoding,$dst_encoding_txt);
356 0           $str.=" name=\"$file_name_str\"".$line_delimiter;
357             }
358 0           $str.="Content-Transfer-Encoding: base64".$line_delimiter;
359            
360 0 0         if(defined($file->{content_id})){
361 0           $str.="Content-ID: <$file->{content_id}>".$line_delimiter;
362             }
363            
364 0           $str.="Content-Disposition: $file->{content_disposion};".$line_delimiter;
365 0 0         if(defined($file->{file_name})){
366 0           $str.=" filename=\"$file_name_str\"".$line_delimiter;
367             }
368            
369 0           $str.=$line_delimiter;
370 0           $str.=_my_chunk_split(MIME::Base64::encode_base64($file->{file_bin},''),$line_delimiter,72);
371 0           $str.=$line_delimiter;
372            
373 0           return $str;
374             }
375            
376             sub parse_part_text($$$$$$){
377 0     0 0   my ($type,$text,$src_encoding,$dst_encoding,$dst_encoding_txt,$line_delimiter)=@_;
378 0           $text=trim($text);
379 0 0         if(!defined($text)){$text='';}
  0            
380             #change encoding
381 0           $text=change_encoding($text,$src_encoding,$dst_encoding);
382            
383 0           my $header_transfer_encoding;
384 0 0         if($text=~/^[\000-\177]*$/){
385 0           $header_transfer_encoding=gen_header('Content-Transfer-Encoding','7bit',$line_delimiter);
386             }else{
387 0           $header_transfer_encoding=gen_header('Content-Transfer-Encoding','8bit',$line_delimiter);
388             }
389            
390 0           my $header_content_type;
391 0 0 0       if(($_all_ascii)&&($text=~/^[\040-\176\r\t\n]*$/)){
392             #all ascii
393             }else{
394 0           $_all_ascii=&_name_false;
395             }
396            
397 0 0         if($type eq 'html'){
    0          
398 0 0         my $encoding=$_all_ascii?'us-ascii':$dst_encoding_txt;
399 0           $header_content_type=gen_header('Content-Type',"text/html; charset=$encoding;",$line_delimiter);
400             }elsif($type eq 'plain'){
401 0 0         my $encoding=$_all_ascii?'us-ascii':$dst_encoding_txt;
402 0           $header_content_type=gen_header('Content-Type',"text/plain; charset=$encoding;",$line_delimiter);
403             }else{
404 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: BUG please report it:unknow type');
405             }
406            
407 0           $text=~s/\r\n/\n/g;
408 0           $text=~s/\r/\n/g;
409 0           $text=~s/\n/$line_delimiter/g;
410 0           $text.=$line_delimiter;
411 0           $text.=$line_delimiter;
412 0           return ($header_transfer_encoding,$header_content_type,$text);
413             }
414            
415             sub sendmail($){
416 0     0 0   my ($param)=@_;
417            
418             #===get sender & config
419 0           my $sender=EasyMail::Sender::get_sender($param);
420 0           my $config=EasyMail::Sender::parse_sender($sender);
421            
422 0           my $line_delimiter=$config->{line_delimiter};
423 0           my $hide_bcc_flag =$config->{hide_bcc};
424             #======================
425            
426             #======================
427 0           my $from_email;
428             my $ra_to;
429 0           my $ra_cc;
430 0           my $ra_bcc;
431             #======================
432            
433             #===temp variable
434 0           my $str;
435             #======================
436            
437 0           my $_mime_boundary= 100000;
438            
439 0           $_all_ascii=&_name_true;
440            
441             #===analyse attachment
442 0           my $mixed_files=[];
443 0           my $related_files=[];
444 0 0         if(defined($param->{files})){
445 0           foreach my $file(@{$param->{files}}){
  0            
446 0           my ($f,$flag)=_process_file($file);
447 0 0         if($flag==0){
    0          
448 0           push @$mixed_files,$f;
449             }elsif($flag==1){
450 0           push @$related_files,$f;
451             }
452             }
453             }
454            
455 0           my $src_encoding=$param->{src_encoding};
456             #if all param is unicode ,may be no need to set src encoding
457            
458 0           my $dst=$param->{dst};
459 0 0         if(!defined($dst)){
460 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: dst must be set in (un,jp,cn)');
461             }
462            
463 0           my ($dst_encoding,$dst_encoding_txt);
464 0 0         if($dst eq 'un'){
    0          
    0          
465 0           $dst_encoding='utf8';$dst_encoding_txt='utf-8';
  0            
466             }elsif($dst eq 'cn'){
467 0           $dst_encoding='gbk';$dst_encoding_txt='gb2312';
  0            
468             }elsif($dst eq 'jp'){
469 0           $dst_encoding='iso-2022-jp';$dst_encoding_txt=$dst_encoding;
  0            
470             }else{
471 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: dst must be set in (un,jp,cn)');
472             }
473            
474 0           my $mail='';
475             #Return-Path
476 0           $mail.=gen_header('Return-Path',$param->{return_path},$line_delimiter);
477 0           my ($email,$name)=parse_email_name_pair($param->{from});
478 0 0         if(!defined($email)){
479 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: must spcify from email');
480             }
481             #From
482 0           ($str,$from_email)=gen_email_name_pair($email,$name,$src_encoding,$dst_encoding,$dst_encoding_txt);
483 0           $mail.=gen_header('From',$str,$line_delimiter);
484 0 0         if (defined($param->{mail_filter})){
485 0 0         if (ref $param->{mail_filter} eq 'ARRAY'){
486 0           $param->{to} = _filter_mail($param->{mail_filter}, $param->{to});
487 0           $param->{cc} = _filter_mail($param->{mail_filter}, $param->{cc});
488 0           $param->{bcc} = _filter_mail($param->{mail_filter}, $param->{bcc});
489             }
490             }
491            
492 0           ($str,$ra_to)=gen_email_name_pair_list($param->{to},$src_encoding,$dst_encoding,$dst_encoding_txt);
493             #To&CC
494 0           $mail.=gen_header('To',$str,$line_delimiter);
495 0           ($str,$ra_cc)=gen_email_name_pair_list($param->{cc},$src_encoding,$dst_encoding,$dst_encoding_txt);
496 0           $mail.=gen_header('CC',$str,$line_delimiter);
497 0 0 0       if ((scalar(@$ra_to)==0) && (scalar(@$ra_cc)==0) ){
498 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: to and cc must contains more than one valid email');
499             }
500            
501             #BCC
502 0           ($str,$ra_bcc)=gen_email_name_pair_list($param->{bcc},$src_encoding,$dst_encoding,$dst_encoding_txt);
503 0 0         if(!$hide_bcc_flag){$mail.=gen_header('BCC',$str,$line_delimiter);}
  0            
504            
505             #Subject
506 0           my $subject=$param->{subject};
507 0 0         if(!defined($subject)){$subject='No Subject';}
  0            
508 0           $mail.=gen_header('Subject',encode_header($subject,$src_encoding,$dst_encoding,$dst_encoding_txt),$line_delimiter);
509             #Date
510 0           $mail.=gen_header('Date',gen_date(),$line_delimiter);
511             #MIME-Version
512 0           $mail.=gen_header('MIME-Version','1.0',$line_delimiter);
513            
514 0           my $type;
515 0 0 0       if(!defined($param->{type})){
    0 0        
    0          
516 0           $type='plain';
517             }elsif($param->{type} eq 'html'){
518 0           $type='html';
519             }elsif(($param->{type} eq 'plain')||($param->{type} eq 'text')||($param->{type} eq 'txt')){
520 0           $type='plain';
521             }else{
522 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: please set type in (plain,html)');
523             }
524            
525 0           my $text=$param->{body};
526 0 0         if(!defined($text)){$text='';}
  0            
527            
528 0           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);
529            
530 0           my $body;
531 0           my ($header_transfer_encoding,$header_content_type);
532            
533 0 0         if(scalar(@$mixed_files)>=1){
    0          
534 0           my $mime_boundary=gen_mime_boundary($_mime_boundary++);
535 0           $header_content_type=gen_header('Content-Type','multipart/mixed;'.$line_delimiter.' boundary="'.$mime_boundary.'"',$line_delimiter);
536 0           $header_transfer_encoding='';
537 0           $body="This is a multi-part message in MIME format".$line_delimiter.$line_delimiter;
538 0           $body.="--".$mime_boundary.$line_delimiter;
539 0 0         if(scalar(@$related_files)>=1){
540 0           my $mime_boundary=gen_mime_boundary($_mime_boundary++);
541 0           $body.=gen_header('Content-Type','multipart/related;'.$line_delimiter.' boundary="'.$mime_boundary.'"',$line_delimiter);
542 0           $body.=$line_delimiter;
543 0           $body.="--".$mime_boundary.$line_delimiter;
544 0           $body.=$text_header_content_type;
545 0           $body.=$text_header_transfer_encoding;
546 0           $body.=$line_delimiter;
547 0           $body.=$text_body;
548 0           foreach(@$related_files){
549 0           $body.="--".$mime_boundary.$line_delimiter;
550 0           $body.=gen_part_file($_,$src_encoding,$dst_encoding,$dst_encoding_txt,$line_delimiter);
551             }
552 0           $body.="--".$mime_boundary."--".$line_delimiter.$line_delimiter;
553             }else{
554 0           $body.=$text_header_content_type;
555 0           $body.=$text_header_transfer_encoding;
556 0           $body.=$line_delimiter;
557 0           $body.=$text_body;
558             }
559 0           foreach(@$mixed_files){
560 0           $body.="--".$mime_boundary.$line_delimiter;
561 0           $body.=gen_part_file($_,$src_encoding,$dst_encoding,$dst_encoding_txt,$line_delimiter);
562             }
563 0           $body.="--".$mime_boundary."--".$line_delimiter;
564             }elsif(scalar(@$related_files)>=1){
565 0           my $mime_boundary=gen_mime_boundary($_mime_boundary++);
566 0           $header_content_type=gen_header('Content-Type','multipart/related;'.$line_delimiter.' boundary="'.$mime_boundary.'"',$line_delimiter);
567 0           $header_transfer_encoding='';
568 0           $body="This is a multi-part message in MIME format".$line_delimiter.$line_delimiter;
569 0           $body.="--".$mime_boundary.$line_delimiter;
570 0           $body.=$text_header_content_type;
571 0           $body.=$text_header_transfer_encoding;
572 0           $body.=$line_delimiter;
573 0           $body.=$text_body;
574 0           foreach(@$related_files){
575 0           $body.="--".$mime_boundary.$line_delimiter;
576 0           $body.=gen_part_file($_,$src_encoding,$dst_encoding,$dst_encoding_txt,$line_delimiter);
577             }
578 0           $body.="--".$mime_boundary."--".$line_delimiter;
579             }else{
580 0           $header_content_type=$text_header_content_type;
581 0           $header_transfer_encoding=$text_header_transfer_encoding;
582 0           $body.=$line_delimiter;
583 0           $body=$text_body;
584             }
585             #Content-Type
586 0           $mail.=$header_content_type;
587             #Transfer-Encoding
588 0           $mail.=$header_transfer_encoding;
589             #Other
590 0           $mail.=gen_header('X-Mailer',_name_pkg_name(),$line_delimiter);
591 0           $mail.=$line_delimiter;
592            
593             #Body
594 0           $mail.=$body;
595            
596 0           my $m=EasyMail::Sender::get_mail($sender,$mail,$from_email,$ra_to,$ra_cc,$ra_bcc);
597 0           EasyMail::Sender::sendmail($m);
598             }
599            
600             sub _filter_mail($$){
601 0     0     my ($ra_filter, $email_list) = @_;
602 0           my $ra_filter_str = [];
603 0           foreach(@$ra_filter){
604 0 0         if (! /^([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/){
605 0           next;
606             }
607 0           push @$ra_filter_str, '@'.$_;
608             }
609            
610 0 0 0       if((ref $email_list eq '')||(ref $email_list eq 'HASH')){
    0          
611 0           my ($email,$name)=parse_email_name_pair($email_list);
612 0 0         return undef if (!defined($email)); #==2.4.2==
613 0           foreach (@$ra_filter_str){
614 0 0         if (index($email, $_) != -1){return $email_list;}
  0            
615             }
616 0           return undef;
617             }elsif(ref $email_list eq 'ARRAY'){
618 0 0         if(scalar(@$email_list)==2){
  0 0          
619 0           my ($A,$B)=(trim($email_list->[0]),trim($email_list->[1]));
620 0 0 0       if(((is_email($A))&&(!is_email($B)))||((!is_email($A))&&(is_email($B)))){
      0        
      0        
621 0           my ($email,$name)=parse_email_name_pair($email_list);
622 0           foreach (@$ra_filter_str){
623 0 0         if (index($email, $_) != -1){return $email_list;}
  0            
624             }
625 0           return undef;
626             }
627             }elsif(scalar(@$email_list)==0){return $email_list;}
628             }else{
629 0           return $email_list;
630             }
631 0           my $filter_email_list = [];
632 0           foreach (@$email_list) {
633 0           my $remain = 0;
634 0           my ($email,$name)=parse_email_name_pair($_);
635 0           foreach (@$ra_filter_str){
636 0 0         if (index($email, $_) != -1){
637 0           $remain = 1;
638 0           last;
639             }
640             }
641 0 0         if ($remain){
642 0           push @$filter_email_list, $_;
643             }
644             }
645            
646 0           return $filter_email_list;
647             }
648            
649             #please use simple char in file_path and file_name
650             sub _process_file($){
651 0     0     my ($file)=@_;
652 0           my $attachment={};
653 0 0 0       if(defined($file->{file_bin})&&defined($file->{file_path})){
    0          
    0          
654 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'_process_file: file_bin and file_path can only set one');
655             }elsif(defined($file->{file_path})){
656 0           my $fh=FileHandle->new($file->{file_path},'r');
657 0 0         if(!defined($fh)){
658 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'_process_file: open attach file failed');
659             }
660 0           my $buf;
661 0           $fh->read($buf,$_max_file_len);
662 0           $fh->close();
663 0           $attachment->{file_bin}=$buf;
664 0           undef $buf;
665 0 0         if(defined($file->{file_name})){
666 0           $attachment->{file_name}=trim($file->{file_name});
667             }else{
668 0           $attachment->{file_name}=File::Basename::basename(trim($file->{file_path}));
669             }
670             }elsif(defined($file->{file_bin})){
671 0           $attachment->{file_bin}=$file->{file_bin};
672 0           $attachment->{file_name}=trim($file->{file_name});
673             }else{
674 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'_process_file: file_bin and file_path must set one');
675             }
676            
677             #===if u don't set file_name please set content_type
678 0 0         if(defined($file->{content_type})){
    0          
679 0           $attachment->{content_type}=$file->{content_type};
680             }elsif(defined($attachment->{file_name})){
681 0           $attachment->{content_type}=guess_file_content_type($attachment->{file_name});
682             }else{
683 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'_process_file: if u don\'t set file_name please set content_type');
684             }
685            
686 0 0         if(defined($file->{content_id})){
687 0           $attachment->{content_id}=$file->{content_id};
688 0           $attachment->{content_disposion}='inline';
689 0           delete $attachment->{file_name};
690             }else{
691 0           $attachment->{content_disposion}='attachment';
692             #===attachment must have a file name
693 0 0         if(!defined($attachment->{file_name})){
694 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'_process_file: please set file_name');
695             }
696             }
697 0 0         return ($attachment,$attachment->{content_id}?1:0);
698             }
699            
700             1;
701            
702             package EasyMail::Sender;
703 1     1   12 use strict;
  1         2  
  1         42  
704 1     1   5 use warnings(FATAL=>'all');
  1         2  
  1         10840  
705            
706 0     0     sub foo{1};
707 0     0     sub _name_pkg_name{'EasyMail::Sender'}
708 0     0     sub _name_true{1;}
709 0     0     sub _name_false{'';}
710            
711             #mail option
712             #SENDMAIL
713             # sendmail_path
714             # sendmail_use_close
715             # sendmail_mail
716             #SMTPAUTHLOGIN | SMTPAUTHPLAIN | SMTPAUTHNONE
717             # smtp_host
718             # smtp_port
719             # print_msg
720             # smtp_mail
721             # from
722             # ra_to
723             # ra_cc
724             # ra_bcc
725             # smtp_usr (SMTPAUTHLOGIN | SMTPAUTHPLAIN)
726             # smtp_pass(SMTPAUTHLOGIN | SMTPAUTHPLAIN)
727             #
728             #DIRECT
729             #
730            
731             sub sendmail($){
732 0     0     my $param_count=scalar(@_);
733 0 0         if($param_count==1){
734 0 0         if($_[0]->{type} eq 'SMTPAUTHLOGIN'){
    0          
    0          
    0          
    0          
735 0           _smtp_AUTH_LOGIN($_[0]);
736             }elsif($_[0]->{type} eq 'SMTPAUTHPLAIN'){
737 0           _smtp_AUTH_PLAIN($_[0]);
738             }elsif($_[0]->{type} eq 'SMTPAUTHNONE'){
739 0           _smtp_AUTH_NONE($_[0]);
740             }elsif($_[0]->{type} eq 'SENDMAIL'){
741 0           _sendmail($_[0]);
742             }elsif($_[0]->{type} eq 'DIRECT'){
743 0           _direct_send($_[0]);
744             }else{
745 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: unknow sender type ');
746             }
747             }else{
748 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: param count should be 1');
749             }
750             }
751            
752             sub get_sender($){
753 0     0     my $param_count=scalar(@_);
754 0 0         if($param_count==1){
755 0           my $sender={};
756 0           my $type=$_[0]->{sender_type};
757 0 0         if(!defined($type)){$type='SENDMAIL';}
  0            
758 0 0         if($type eq 'SENDMAIL'){
    0          
    0          
    0          
    0          
759 0           $sender->{type}='SENDMAIL';
760 0 0         $sender->{sendmail_path}=defined($_[0]->{sendmail_path})?$_[0]->{sendmail_path}:'sendmail';
761 0 0 0       $sender->{sendmail_use_close}=((!defined($_[0]->{sendmail_use_close}))||($_[0]->{sendmail_use_close}))?&_name_true:&_name_false;
762 0           return $sender;
763             }elsif($type eq 'SMTPAUTHLOGIN'){
764 0           $sender->{type}='SMTPAUTHLOGIN';
765 0 0         $sender->{smtp_host}=defined($_[0]->{smtp_host})?$_[0]->{smtp_host}:'127.0.0.1';
766 0 0         $sender->{smtp_port}=defined($_[0]->{smtp_port})?$_[0]->{smtp_port}:25;
767 0 0 0       $sender->{print_msg}=(defined($_[0]->{print_msg})&&$_[0]->{print_msg})?&_name_true:&_name_false;
768 0           $sender->{smtp_usr}=$_[0]->{smtp_usr};
769 0 0         if(!defined($sender->{smtp_usr})){
770 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: smtp_usr must set');
771             }
772 0           $sender->{smtp_pass}=$_[0]->{smtp_pass};
773 0 0         if(!defined($sender->{smtp_pass})){
774 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: smtp_pass must set');
775             }
776 0           return $sender;
777             }elsif($type eq 'SMTPAUTHPLAIN'){
778 0           $sender->{type}='SMTPAUTHPLAIN';
779 0 0         $sender->{smtp_host}=defined($_[0]->{smtp_host})?$_[0]->{smtp_host}:'127.0.0.1';
780 0 0         $sender->{smtp_port}=defined($_[0]->{smtp_port})?$_[0]->{smtp_port}:25;
781 0 0 0       $sender->{print_msg}=(defined($_[0]->{print_msg})&&$_[0]->{print_msg})?&_name_true:&_name_false;
782 0           $sender->{smtp_usr}=$_[0]->{smtp_usr};
783 0 0         if(!defined($sender->{smtp_usr})){
784 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: smtp_usr must set');
785             }
786 0           $sender->{smtp_pass}=$_[0]->{smtp_pass};
787 0 0         if(!defined($sender->{smtp_pass})){
788 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: smtp_pass must set');
789             }
790 0           return $sender;
791             }elsif($type eq 'SMTPAUTHNONE'){
792 0           $sender->{type}='SMTPAUTHNONE';
793 0 0         $sender->{smtp_host}=defined($_[0]->{smtp_host})?$_[0]->{smtp_host}:'127.0.0.1';
794 0 0         $sender->{smtp_port}=defined($_[0]->{smtp_port})?$_[0]->{smtp_port}:25;
795 0 0 0       $sender->{print_msg}=(defined($_[0]->{print_msg})&&$_[0]->{print_msg})?&_name_true:&_name_false;
796 0           return $sender;
797             }elsif($type eq 'DIRECT'){
798 0           $sender->{type}='DIRECT';
799             #$sender->{smtp_host}=defined($_[0]->{smtp_host})?$_[0]->{smtp_host}:'127.0.0.1';
800             #$sender->{smtp_port}=defined($_[0]->{smtp_port})?$_[0]->{smtp_port}:25;
801 0 0 0       $sender->{print_msg}=(defined($_[0]->{print_msg})&&$_[0]->{print_msg})?&_name_true:&_name_false;
802 0           return $sender;
803             }else{
804 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: unknow sender type');
805             }
806             }else{
807 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: param count should be 1');
808             }
809             }
810            
811             sub get_mail($$$$$$){
812 0     0     my $param_count=scalar(@_);
813 0 0         if($param_count==6){
814 0           my $type=$_[0]->{type};
815 0 0         if($type eq 'SENDMAIL'){
    0          
    0          
    0          
    0          
816 0           $_[0]->{sendmail_mail}=$_[1];
817 0           return $_[0];
818             }elsif($type eq 'SMTPAUTHLOGIN'){
819 0           $_[0]->{smtp_mail}=$_[1];
820 0           $_[0]->{from}=$_[2];
821 0           $_[0]->{ra_to}=$_[3];
822 0           $_[0]->{ra_cc}=$_[4];
823 0           $_[0]->{ra_bcc}=$_[5];
824 0           return $_[0];
825             }elsif($type eq 'SMTPAUTHPLAIN'){
826 0           $_[0]->{smtp_mail}=$_[1];
827 0           $_[0]->{from}=$_[2];
828 0           $_[0]->{ra_to}=$_[3];
829 0           $_[0]->{ra_cc}=$_[4];
830 0           $_[0]->{ra_bcc}=$_[5];
831 0           return $_[0];
832             }elsif($type eq 'SMTPAUTHNONE'){
833 0           $_[0]->{smtp_mail}=$_[1];
834 0           $_[0]->{from}=$_[2];
835 0           $_[0]->{ra_to}=$_[3];
836 0           $_[0]->{ra_cc}=$_[4];
837 0           $_[0]->{ra_bcc}=$_[5];
838 0           return $_[0];
839             }elsif($type eq 'DIRECT'){
840 0           $_[0]->{smtp_mail}=$_[1];
841 0           $_[0]->{from}=$_[2];
842 0           $_[0]->{ra_to}=$_[3];
843 0           $_[0]->{ra_cc}=$_[4];
844 0           $_[0]->{ra_bcc}=$_[5];
845 0           return $_[0];
846             }else{
847 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: unknow sender type');
848             }
849             }else{
850 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: param count should be 6');
851             }
852             }
853            
854             sub parse_sender($){
855 0     0     my $type=$_[0]->{type};
856 0 0 0       if(!defined($type)){
    0 0        
    0 0        
857 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: unknow sender type');
858             }elsif($type eq 'SENDMAIL'){
859 0           return {line_delimiter=>"\n",hide_bcc=>&_name_false};
860             }elsif(($type eq 'SMTPAUTHLOGIN')||($type eq 'SMTPAUTHPLAIN')||($type eq 'SMTPAUTHNONE')||($type eq 'DIRECT') ){
861 0           return {line_delimiter=>"\r\n",hide_bcc=>&_name_true};
862             }else{
863 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: unknow sender type');
864             }
865             }
866            
867             sub _direct_send {
868 0     0     my ($mail) = @_;
869 0           my $email = $mail->{'ra_to'}->[0];
870 0 0         if ($email =~ /^[a-zA-Z0-9\_\.\-]+\@((?:[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6})$/){
871 0           my $address = lc($1);
872 0           require Net::DNS;
873 0           my @mx = Net::DNS::mx($address);
874 0 0         if (scalar(@mx)==0){
875 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: cannot parse mx record!');
876             } else {
877 0           $mail->{'ra_to'} = [$email];
878 0           $mail->{'sender_type'} = 'SMTPAUTHNONE';
879 0           $mail->{'smtp_host'} = $mx[0]->exchange;
880 0           $mail->{smtp_port}=25;
881 0           _smtp_AUTH_NONE($mail);
882 0           return;
883             }
884             }else{
885 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: BUG!');
886             }
887             }
888            
889             sub _smtp_AUTH_LOGIN($){
890 0     0     my ($mail)=@_;
891 0 0         my $smtp_host=defined($mail->{smtp_host})?$mail->{smtp_host}:'localhost';
892 0 0         my $smtp_port=defined($mail->{smtp_port})?$mail->{smtp_port}:25;
893 0 0         my $print_msg=defined($mail->{print_msg})?$mail->{print_msg}:0;
894 0           my $sock=new IO::Socket::INET->new(PeerPort=>$smtp_port,Proto=>'tcp',PeerAddr=>$smtp_host);
895 0 0         if(!defined($sock)){CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: cannot connect to smtp server!');}
  0 0          
896            
897 0           _server_parse($sock, "220",$print_msg,__LINE__);
898 0           _server_send($sock,"EHLO $mail->{smtp_host}\r\n",$print_msg,__LINE__);
899 0           _server_parse($sock, "250",$print_msg,__LINE__);
900 0           _server_send($sock,"AUTH LOGIN\r\n",$print_msg,__LINE__);
901 0           _server_parse($sock, "334",$print_msg,__LINE__);
902 0           _server_send($sock,MIME::Base64::encode_base64($mail->{smtp_usr},'')."\r\n",$print_msg,__LINE__);
903 0           _server_parse($sock, "334",$print_msg,__LINE__);
904 0           _server_send($sock,MIME::Base64::encode_base64($mail->{smtp_pass},'')."\r\n",$print_msg,__LINE__);
905 0           _server_parse($sock, "235",$print_msg,__LINE__);
906 0           _server_send($sock,"MAIL FROM: <$mail->{from}>\r\n",$print_msg,__LINE__);
907 0           _server_parse($sock, "250",$print_msg,__LINE__);
908            
909 0           foreach my $to(@{$mail->{ra_to}}){
  0            
910 0           _server_send($sock,"RCPT TO: <$to>\r\n",$print_msg,__LINE__);
911 0           _server_parse($sock, "250",$print_msg,__LINE__);
912             }
913 0           foreach my $cc(@{$mail->{ra_cc}}){
  0            
914 0           _server_send($sock,"RCPT TO: <$cc>\r\n",$print_msg,__LINE__);
915 0           _server_parse($sock, "250",$print_msg,__LINE__);
916             }
917 0           foreach my $bcc(@{$mail->{ra_bcc}}){
  0            
918 0           _server_send($sock,"RCPT TO: <$bcc>\r\n",$print_msg,__LINE__);
919 0           _server_parse($sock, "250",$print_msg,__LINE__);
920             }
921            
922 0           _server_send($sock,"DATA\r\n",$print_msg,__LINE__);
923 0           _server_parse($sock, "354",$print_msg,__LINE__);
924 0           _server_send($sock,$mail->{smtp_mail}."\r\n.\r\n",$print_msg,__LINE__);
925 0           _server_parse($sock, "250",$print_msg,__LINE__);
926 0           _server_send($sock,"QUIT\r\n",$print_msg,__LINE__);
927 0           _server_parse($sock, "221",$print_msg,__LINE__);
928 0           $sock->shutdown(2);
929             }
930            
931             sub _smtp_AUTH_PLAIN($){
932 0     0     my ($mail)=@_;
933 0 0         my $smtp_host=defined($mail->{smtp_host})?$mail->{smtp_host}:'localhost';
934 0 0         my $smtp_port=defined($mail->{smtp_port})?$mail->{smtp_port}:25;
935 0 0         my $print_msg=defined($mail->{print_msg})?$mail->{print_msg}:0;
936 0           my $sock=new IO::Socket::INET->new(PeerPort=>$smtp_port,Proto=>'tcp',PeerAddr=>$smtp_host);
937 0 0         if(!defined($sock)){CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: cannot connect to smtp server!');}
  0 0          
938            
939 0           _server_parse($sock, "220",$print_msg,__LINE__);
940 0           _server_send($sock,"EHLO $mail->{smtp_host}\r\n",$print_msg,__LINE__);
941 0           _server_parse($sock, "250",$print_msg,__LINE__);
942 0           _server_send($sock,"AUTH PLAIN ".MIME::Base64::encode_base64(join("\0",$mail->{smtp_usr},$mail->{smtp_pass})),$print_msg,__LINE__);
943 0           _server_parse($sock, "235",$print_msg,__LINE__);
944 0           _server_send($sock,"MAIL FROM: <$mail->{from}>\r\n",$print_msg,__LINE__);
945 0           _server_parse($sock, "250",$print_msg,__LINE__);
946            
947 0           foreach my $to(@{$mail->{ra_to}}){
  0            
948 0           _server_send($sock,"RCPT TO: <$to>\r\n",$print_msg,__LINE__);
949 0           _server_parse($sock, "250",$print_msg,__LINE__);
950             }
951 0           foreach my $cc(@{$mail->{ra_cc}}){
  0            
952 0           _server_send($sock,"RCPT TO: <$cc>\r\n",$print_msg,__LINE__);
953 0           _server_parse($sock, "250",$print_msg,__LINE__);
954             }
955 0           foreach my $bcc(@{$mail->{ra_bcc}}){
  0            
956 0           _server_send($sock,"RCPT TO: <$bcc>\r\n",$print_msg,__LINE__);
957 0           _server_parse($sock, "250",$print_msg,__LINE__);
958             }
959            
960 0           _server_send($sock,"DATA\r\n",$print_msg,__LINE__);
961 0           _server_parse($sock, "354",$print_msg,__LINE__);
962 0           _server_send($sock,$mail->{smtp_mail}."\r\n.\r\n",$print_msg,__LINE__);
963 0           _server_parse($sock, "250",$print_msg,__LINE__);
964 0           _server_send($sock,"QUIT\r\n",$print_msg,__LINE__);
965 0           _server_parse($sock, "221",$print_msg,__LINE__);
966 0           $sock->shutdown(2);
967             }
968            
969             sub _smtp_AUTH_NONE($){
970 0     0     my ($mail)=@_;
971 0 0         my $smtp_host=defined($mail->{smtp_host})?$mail->{smtp_host}:'localhost';
972 0 0         my $smtp_port=defined($mail->{smtp_port})?$mail->{smtp_port}:25;
973 0 0         my $print_msg=defined($mail->{print_msg})?$mail->{print_msg}:0;
974 0           my $sock=new IO::Socket::INET->new(PeerPort=>$smtp_port,Proto=>'tcp',PeerAddr=>$smtp_host);
975 0 0         if(!defined($sock)){CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: cannot connect to smtp server!');}
  0 0          
976            
977 0           _server_parse($sock, "220",$print_msg,__LINE__);
978 0           _server_send($sock,"EHLO $mail->{smtp_host}\r\n",$print_msg,__LINE__);
979 0           _server_parse($sock, "250",$print_msg,__LINE__);
980 0           _server_send($sock,"MAIL FROM: <$mail->{from}>\r\n",$print_msg,__LINE__);
981 0           _server_parse($sock, "250",$print_msg,__LINE__);
982            
983 0           foreach my $to(@{$mail->{ra_to}}){
  0            
984 0           _server_send($sock,"RCPT TO: <$to>\r\n",$print_msg,__LINE__);
985 0           _server_parse($sock, "250",$print_msg,__LINE__);
986             }
987 0           foreach my $cc(@{$mail->{ra_cc}}){
  0            
988 0           _server_send($sock,"RCPT TO: <$cc>\r\n",$print_msg,__LINE__);
989 0           _server_parse($sock, "250",$print_msg,__LINE__);
990             }
991 0           foreach my $bcc(@{$mail->{ra_bcc}}){
  0            
992 0           _server_send($sock,"RCPT TO: <$bcc>\r\n",$print_msg,__LINE__);
993 0           _server_parse($sock, "250",$print_msg,__LINE__);
994             }
995            
996 0           _server_send($sock,"DATA\r\n",$print_msg,__LINE__);
997 0           _server_parse($sock, "354",$print_msg,__LINE__);
998 0           _server_send($sock,$mail->{smtp_mail}."\r\n.\r\n",$print_msg,__LINE__);
999 0           _server_parse($sock, "250",$print_msg,__LINE__);
1000 0           _server_send($sock,"QUIT\r\n",$print_msg,__LINE__);
1001 0           _server_parse($sock, "221",$print_msg,__LINE__);
1002 0           $sock->shutdown(2);
1003             }
1004            
1005             sub _sendmail($){
1006 0     0     my ($mail,$path,$use_close)=($_[0]->{sendmail_mail},$_[0]->{sendmail_path},$_[0]->{sendmail_use_close});
1007 0 0         $path=defined($path)?$path:'sendmail';
1008 0           eval{
1009 0 0         if(!open(MAIL, "| $path -t")){
1010 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: sendmail_path not valid');
1011             }
1012             };
1013 0 0         if($@){
1014 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: sendmail_path not valid');
1015             }
1016 0           print MAIL $mail;
1017 0           undef $mail;
1018 0 0 0       unless(defined($use_close)&&$use_close==0){close(MAIL);}
  0            
1019             }
1020            
1021             sub _server_parse($$$$){
1022 0     0     my ($socket, $response,$print_msg,$line)=@_;
1023 0           my $server_response;
1024 0           $socket->recv($server_response, 4096);
1025 0 0         if(!defined($server_response)){
1026 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: couldn\'t get mail server response codes');
1027             }
1028 0           my @response_lines=split(/\015?\012/, $server_response, -1);
1029 0           my $code;
1030 0           while(1){
1031 0           my $response_line=shift @response_lines;
1032 0 0         if(!defined($response_line)){last;}
  0            
1033 0 0         if($print_msg){print $response_line."\n";}
  0            
1034 0 0         if($response_line=~ s/^(\d\d\d)(.?)//o){if($2 ne "-"){$code=$1;last;}}
  0 0          
  0            
  0            
1035             }
1036             #qian.yu
1037 0 0 0       if (!(defined($code) && defined($response) && ($code eq $response) )){
1038 0 0         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 ");
1039             }
1040             };
1041            
1042             sub _server_send($$$){
1043 0     0     my ($socket,$msg,$print_msg,$line)=@_;
1044 0 0         if($print_msg){
1045 0           print trim($msg)."\n";
1046             }
1047 0 0         if(!$socket->send($msg)){
1048 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'sendmail: send command to server error');
1049             };
1050             }
1051            
1052             sub trim($) {
1053 0     0     my $param_count=scalar(@_);
1054 0 0         if($param_count==1){
1055 0           local $_=$_[0];
1056 0 0         unless(defined($_)){return undef;}
  0            
1057 0           s/^\s+//,s/\s+$//;
1058 0           return $_ ;
1059             }else{
1060 0 0         CORE::die((defined(&_name_pkg_name)?&_name_pkg_name.'::':'').'trim: param count should be 1');
1061             }
1062             }
1063            
1064             1;
1065            
1066             __END__