File Coverage

lib/Mojolicious/Plugin/Mail.pm
Criterion Covered Total %
statement 92 93 98.9
branch 32 40 80.0
condition 34 55 61.8
subroutine 13 13 100.0
pod 2 2 100.0
total 173 203 85.2


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::Mail;
2 1     1   1451 use Mojo::Base 'Mojolicious::Plugin';
  1         11  
  1         7  
3              
4 1     1   1395 use MIME::Lite;
  1         24227  
  1         29  
5 1     1   788 use MIME::EncWords ();
  1         11586  
  1         28  
6 1     1   8 use Mojo::ByteStream 'b';
  1         2  
  1         56  
7              
8 1   50 1   5 use constant TEST => $ENV{MOJO_MAIL_TEST} || 0;
  1         2  
  1         61  
9 1     1   4 use constant FROM => 'test-mail-plugin@mojolicio.us';
  1         2  
  1         37  
10 1     1   5 use constant CHARSET => 'UTF-8';
  1         1  
  1         36  
11 1     1   3 use constant ENCODING => 'base64';
  1         2  
  1         2672  
12              
13             our $VERSION = '1.3';
14              
15             has conf => sub { +{} };
16              
17             sub register {
18 1     1 1 56 my ($plugin, $app, $conf) = @_;
19            
20             # default values
21 1   50     6 $conf->{from } ||= FROM;
22 1   50     8 $conf->{charset } ||= CHARSET;
23 1   50     4 $conf->{encoding} ||= ENCODING;
24            
25 1 50       21 $plugin->conf( $conf ) if $conf;
26            
27             $app->helper(
28             mail => sub {
29 13     13   386368 my $self = shift;
30 13 100       148 my $args = @_ ? { @_ } : return;
31            
32             # simple interface
33 12 100       70 unless (exists $args->{mail}) {
34             $args->{mail}->{ $_->[1] } = delete $args->{ $_->[0] }
35 8         517 for grep $args->{ $_->[0] },
36             [to => 'To' ], [from => 'From'], [reply_to => 'Reply-To'],
37             [cc => 'Cc' ], [bcc => 'Bcc' ], [subject => 'Subject' ],
38             [data => 'Data'], [type => 'Type'],
39             ;
40             }
41            
42             # hidden data and subject
43            
44 3         15 my @stash =
45 33         172 map { $_ => $args->{$_} }
46 12         108 grep { !/^(to|from|reply_to|cc|bcc|subject|data|type|test|mail|attach|headers|attr|charset|mimeword|nomailer)$/ }
47             keys %$args
48             ;
49            
50 12   100     111 $args->{mail}->{Data } ||= $self->render_mail(@stash);
51 12   66     155 $args->{mail}->{Subject} ||= $self->stash ('subject');
52            
53 12         326 my $msg = $plugin->build( %$args );
54 12   50     53 my $test = $args->{test} || TEST;
55 12 0       29 $msg->send( $conf->{'how'}, @{$conf->{'howargs'}||[]} ) unless $test;
  0 50       0  
56            
57 12         60 $msg->as_string;
58             },
59 1         23 );
60            
61             $app->helper(
62             render_mail => sub {
63 8     8   75621 my $self = shift;
64 8         45 my $data = $self->render_to_string(@_, format => 'mail');
65            
66             # delete @{$self->stash}{ qw(cb format mojo.captures mojo.started mojo.content mojo.routed) };
67 8         11497 $data;
68             },
69 1         99 );
70             }
71              
72             sub build {
73 12     12 1 25 my $self = shift;
74 12         330 my $conf = $self->conf;
75 12         126 my $p = { @_ };
76            
77 12         33 my $mail = $p->{mail};
78 12   66     85 my $charset = $p->{charset } || $conf->{charset };
79 12   33     81 my $encoding = $p->{encoding} || $conf->{encoding};
80 12 50       38 my $encode = $encoding eq 'base64' ? 'B' : 'Q';
81 12 50       51 my $mimeword = defined $p->{mimeword} ? $p->{mimeword} : !$encoding ? 0 : 1;
    100          
82            
83             # tuning
84            
85 12   50     79 $mail->{From} ||= $conf->{from} || '';
      66        
86 12   50     79 $mail->{Type} ||= $conf->{type} || '';
      66        
87            
88 12 100 66     56 if ($mail->{Data} && $mail->{Type} !~ /multipart/) {
89 10   33     120 $mail->{Encoding} ||= $encoding;
90 10         45 _enc($mail->{Data} => $charset);
91             }
92            
93 12 100       37 if ($mimeword) {
94 11         24 $_ = MIME::EncWords::encode_mimeword($_, $encode, $charset)
95 11         28 for grep { _enc($_ => $charset); 1 } $mail->{Subject}
  11         92  
96             ;
97            
98 11         403 for (grep $mail->{$_}, qw(From To Cc Bcc)) {
99 25         51 $mail->{$_} = join ", ",
100             grep {
101 24         113 _enc($_ => $charset);
102             {
103 25 100       28 next unless /(.*) \s+ (\S+ @ .*)/x;
  25         410  
104            
105 3         9 my($name, $email) = ($1, $2);
106 3         17 $email =~ s/(^<+|>+$)//sg;
107            
108 3 100       19 $_ = $name =~ /^[\w\s"'.,]+$/
109             ? "$name <$email>"
110             : MIME::EncWords::encode_mimeword($name, $encode, $charset) . " <$email>"
111             ;
112             }
113 25         127 1;
114             }
115             split /\s*,\s*/, $mail->{$_}
116             ;
117             }
118             }
119            
120             # year, baby!
121            
122 12         129 my $msg = MIME::Lite->new( %$mail );
123            
124             # header
125 12         67337 $msg->delete('X-Mailer'); # remove default MIME::Lite header
126            
127 12 100       232 $msg->add ( %$_ ) for @{$p->{headers} || []}; # XXX: add From|To|Cc|Bcc => ... (mimeword)
  12         91  
128 12 100 100     102 $msg->add ('X-Mailer' => join ' ', 'Mojolicious', $Mojolicious::VERSION, __PACKAGE__, $VERSION, '(Perl)')
129             unless $msg->get('X-Mailer') || $p->{nomailer};
130            
131             # attr
132 12 50       526 $msg->attr( %$_ ) for @{$p->{attr } || []};
  12         76  
133 12 50       71 $msg->attr('content-type.charset' => $charset) if $charset;
134            
135             # attach
136 12         236 $msg->attach( %$_ ) for
137             grep {
138 5 100 100     33 if (!$_->{Type} || $_->{Type} =~ /text/i) {
  5 100       23  
139 2   66     10 $_->{Encoding} ||= $encoding;
140 2         7 _enc($_->{Data} => $charset);
141             }
142 5         18 1;
143             }
144 12 100       72 grep { $_->{Data} || $_->{Path} }
145             @{$p->{attach} || []}
146             ;
147            
148 12         44385 $msg;
149             }
150              
151             sub _enc($$) {
152 48   50 48   116 my $charset = $_[1] || CHARSET;
153 48 100 33     387 $_[0] = b($_[0])->encode('UTF-8')->to_string if $_[0] && $charset && $charset =~ /utf-8/i;
      66        
154 48         1549 $_[0];
155             }
156              
157             1;
158              
159             __END__