package Ernad::Email; use strict; use warnings; use Carp qw(confess); use Data::Dumper; use Encode; use File::Basename; use File::Slurp; #use File::Slurper; use MIME::Entity; use File::Path; use File::Temp qw/ tempfile tempdir /; use Text::Wrapper; ## form issue nucleus sub prepare_email { my $doc=shift; my $sheet_name=shift // ''; my $save_email=shift // ''; my $verbose=shift // ''; $verbose=0; my $e=$main::e or confess 'Where is my erimp?'; my $text_doc; my $html_doc; ## case of a single doc if(ref $doc eq 'XML::LibXML::Document') { $text_doc=$doc; $html_doc=$doc; } else { my $ref_xml; $text_doc=$doc->{'text'}; $ref_xml=ref($text_doc); if(not $ref_xml eq 'XML::LibXML::Document') { confess 'Your doc->{html} is not a document.'; } $html_doc=$doc->{'html'}; $ref_xml=ref($html_doc); if(not $ref_xml eq 'XML::LibXML::Document') { confess 'Your doc->{html} is not a document.'; } } if(not $e) { #$e=$Erimp::e // $main::e; $e=$main::e; } if(not ref($e) eq 'Ernad::Erimp') { confess 'Where is my erimp?'; } if(not ref($e) eq 'Ernad::Erimp') { confess 'Where is my erimp?'; } ## fixme. I have to form the headers from one doc, but ## which one? Here I use the html doc my $headers=&form_headers($html_doc,$e,$sheet_name); my $top = MIME::Entity->build(%$headers); ## create attachments my $sheet_dir=$e->{'dir'}->{'style'}; my $sheet_name_end="_$sheet_name".$e->{'const'}->{'xsl_ext'}; my $sheet_file; ## save file is a path/file expression if($save_email) { my $save_email_dir=dirname($save_email); if(not -d $save_email_dir) { mkpath($save_email_dir); } } ## text first $sheet_file="$sheet_dir/email_text".$sheet_name_end; if(-f $sheet_file) { my $text=&form_body($text_doc,$e,$sheet_name,'text'); my $save_file=$save_email.'.txt'; &File::Slurp::write_file($save_file,$text); $top->attach( Type => 'text/plain', Description => basename($save_email).' text', Charset => 'UTF-8', Path => $save_file, Encoding => '8BIT' ); } else { $e->echo(__LINE__,"I did not find $sheet_file. The text part will be empty."); } ## html $sheet_file="$sheet_dir/email_html".$sheet_name_end; if(-f $sheet_file) { my $html=&form_body($html_doc,$e,$sheet_name,'html'); my $save_file=$save_email.'.html'; my $html_string=$html->toString(); my $wrapper = Text::Wrapper->new(columns => 80, wrap_after=>''); my $wrapped_html_string=$wrapper->wrap($html_string); &File::Slurp::write_file($save_file,$wrapped_html_string); $top->attach( Type => 'text/html', Description => basename($save_email).' HTML', Charset => 'utf-8', Data => $wrapped_html_string, ## do not use Path => $save_file, Encoding => '8BIT' ); } else { $e->echo(__LINE__,"I did not find $sheet_file. The html part will be empty."); } ## general save_file my $save_file; my $save_fh; if($save_email) { $save_file=$save_email.'.mail'; } else { ($save_fh, $save_file) = tempfile(DIR => '/tmp'); } my $contents=$top->stringify; #$contents=decode_utf8($contents); #&File::Slurper::write_text($save_file,$contents,'utf8'); &File::Slurp::write_file($save_file,$contents); if($verbose) { print "wrote $save_file\n"; } return $save_file; } sub send_email { my $mail_file=shift // ''; my $do_delete=shift // ''; if(not $mail_file) { confess 'I have no email file to send.'; } if(not -f $mail_file) { confess "I don't see your file '$mail_file'."; } my $e=$main::e // confess 'Where is my erimp?'; ## sending it out my $exim_path=$e->{'conf'}->{'exim_path'}; my $cmd = "cat $mail_file | $exim_path -t"; ## could also be done by construction a default here ernad at domain my $envelope_from=$e->{'conf'}->{'envelope_from'} // ''; if($envelope_from) { $cmd.=" -f $envelope_from"; } system($cmd); ## remove the temporary file, keep the saved file if($mail_file=~m|^/tmp/| or $do_delete) { unlink $mail_file; } } sub form_headers { my $doc=shift; my $e=shift // ''; my $sheet_name=shift // ''; my $sheet="headers_$sheet_name"; my $headers_doc=$e->{'t'}->transform($doc,$sheet) or confess "My transformation using $sheet failed."; my $headers_xp="/e:headers/e:header"; my $xpc=$e->{'xpc'}; my @headers=$xpc->findnodes($headers_xp,$headers_doc)->get_nodelist(); my $h; foreach my $header (@headers) { #print $header->toString; my $value=$header->getAttribute('value') or next; my $name=$header->getAttribute('name'); ## several headers with the same name are not supported! $h->{$name}=&email_header_encode($value); } #print Dumper $h; return $h; } sub form_body { my $doc=shift; my $e=shift // ''; my $sheet_name=shift // ''; my $type=shift; my $sheet="email_$type"."_$sheet_name"; my $output; if($type eq 'text') { $output=$e->{'t'}->t($doc,$sheet,'chars') or confess "My transformation using $sheet failed."; } else { $output=$e->{'t'}->transform($doc,$sheet) or confess "My transformation using $sheet failed."; } return $output; } ## http://stackoverflow.com/questions/11969775/how-to-encode-mail-subject-in-perl sub email_header_encode { my $string=shift; if($string!~/[^\x00-\x7F]/) { return $string; } ## try separate out the email address if($string=~m|^(.*)\s+(<[^@]+@[^@]+>)$|) { my $name=$1; my $mad=$2; my $name_encoded=encode('MIME-Header', $name); return "$name_encoded $mad"; } ## fallback case return encode('MIME-Header', $string); } 1;