File Coverage

lib/Mojolicious/Plugin/Mail.pm
Criterion Covered Total %
statement 90 91 98.9
branch 32 40 80.0
condition 34 55 61.8
subroutine 13 13 100.0
pod 2 2 100.0
total 171 201 85.0


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