line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Web::Components::Role::Email; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
3112
|
use 5.010001; |
|
1
|
|
|
|
|
2
|
|
4
|
1
|
|
|
1
|
|
4
|
use namespace::autoclean; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
9
|
|
5
|
1
|
|
|
1
|
|
65
|
use version; our $VERSION = qv( sprintf '0.3.%d', q$Rev: 1 $ =~ /\d+/gmx ); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
5
|
|
6
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
769
|
use Email::MIME; |
|
1
|
|
|
|
|
47017
|
|
|
1
|
|
|
|
|
38
|
|
8
|
1
|
|
|
1
|
|
8
|
use Encode qw( encode ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
83
|
|
9
|
1
|
|
|
1
|
|
9
|
use File::DataClass::Constants qw( EXCEPTION_CLASS TRUE ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
60
|
|
10
|
1
|
|
|
1
|
|
5
|
use File::DataClass::Functions qw( ensure_class_loaded is_hashref ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
40
|
|
11
|
1
|
|
|
1
|
|
4
|
use File::DataClass::IO; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
9
|
|
12
|
1
|
|
|
1
|
|
676
|
use MIME::Types; |
|
1
|
|
|
|
|
3395
|
|
|
1
|
|
|
|
|
58
|
|
13
|
1
|
|
|
1
|
|
5
|
use Scalar::Util qw( blessed weaken ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
43
|
|
14
|
1
|
|
|
1
|
|
5
|
use Try::Tiny; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
59
|
|
15
|
1
|
|
|
1
|
|
4
|
use Unexpected::Functions qw( Unspecified throw ); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
9
|
|
16
|
1
|
|
|
1
|
|
380
|
use Moo::Role; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
8
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
requires qw( config log ); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
with 'Web::Components::Role::TT'; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# Private subroutines |
23
|
|
|
|
|
|
|
my $_add_attachments = sub { |
24
|
|
|
|
|
|
|
my ($args, $email) = @_; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
my $types = MIME::Types->new( only_complete => TRUE ); |
27
|
|
|
|
|
|
|
my $part = Email::MIME->create |
28
|
|
|
|
|
|
|
( attributes => $email->{attributes}, body => delete $email->{body} ); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
$email->{parts} = [ $part ]; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
for my $name (sort keys %{ $args->{attachments} }) { |
33
|
|
|
|
|
|
|
my $path = io( $args->{attachments}->{ $name } )->binary->lock; |
34
|
|
|
|
|
|
|
my $mime = $types->mimeTypeOf( my $file = $path->basename ); |
35
|
|
|
|
|
|
|
my $attr = { content_type => $mime->type, |
36
|
|
|
|
|
|
|
encoding => $mime->encoding, |
37
|
|
|
|
|
|
|
filename => $file, |
38
|
|
|
|
|
|
|
name => $name }; |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
$part = Email::MIME->create( attributes => $attr, body => $path->all ); |
41
|
|
|
|
|
|
|
push @{ $email->{parts} }, $part; |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
return; |
45
|
|
|
|
|
|
|
}; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
my $_make_f = sub { |
48
|
|
|
|
|
|
|
my ($obj, $f) = @_; weaken $obj; return sub { $obj->$f( @_ ) }; |
49
|
|
|
|
|
|
|
}; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
my $_stash_functions = sub { |
52
|
|
|
|
|
|
|
my ($self, $obj, $stash, $funcs) = @_; defined $obj or return; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
$funcs //= []; $funcs->[ 0 ] or push @{ $funcs }, 'loc'; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
for my $f (@{ $funcs }) { $stash->{ $f } = $_make_f->( $obj, $f ) } |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
return; |
59
|
|
|
|
|
|
|
}; |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
my $_get_email_body = sub { |
62
|
|
|
|
|
|
|
my ($self, $args) = @_; my $obj = delete $args->{subprovider}; |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
exists $args->{body} and defined $args->{body} and return $args->{body}; |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
$args->{template} or throw Unspecified, [ 'template' ]; |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
my $stash = $args->{stash} //= {}; $stash->{page} //= {}; |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
$stash->{page}->{layout} //= $args->{template}; |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
$_stash_functions->( $self, $obj, $stash, $args->{functions} ); |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
return $self->render_template( $stash ); |
75
|
|
|
|
|
|
|
}; |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
my $_create_email = sub { |
78
|
|
|
|
|
|
|
my ($self, $args) = @_; $args->{email} and return $args->{email}; |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
my $conf = $self->config; |
81
|
|
|
|
|
|
|
my $attr = $conf->can( 'email_attr' ) ? $conf->email_attr : {}; |
82
|
|
|
|
|
|
|
my $email = { attributes => { %{ $attr }, %{ $args->{attributes} // {}}}}; |
83
|
|
|
|
|
|
|
my $from = $args->{from} or throw Unspecified, [ 'from' ]; |
84
|
|
|
|
|
|
|
my $to = $args->{to } or throw Unspecified, [ 'to' ]; |
85
|
|
|
|
|
|
|
my $encoding = $email->{attributes}->{charset}; |
86
|
|
|
|
|
|
|
my $subject = $args->{subject} // 'No subject'; |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
try { $subject = encode( 'MIME-Header', $subject, TRUE ) } |
89
|
|
|
|
|
|
|
catch { throw 'Cannot encode subject as MIME-Header: [_1]', [ $_ ] }; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
$email->{header} = [ From => $from, To => $to, Subject => $subject ]; |
92
|
|
|
|
|
|
|
$email->{body } = $_get_email_body->( $self, $args ); |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
try { |
95
|
|
|
|
|
|
|
$encoding and $email->{body} = encode( $encoding, $email->{body}, TRUE ); |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
catch { throw 'Cannot encode body as [_1]: [_2]', [ $encoding, $_ ] }; |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
exists $args->{attachments} and $_add_attachments->( $args, $email ); |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
return Email::MIME->create( %{ $email } ); |
102
|
|
|
|
|
|
|
}; |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
my $_transport_email = sub { |
105
|
|
|
|
|
|
|
my ($self, $args) = @_; $args->{email} or throw Unspecified, [ 'email' ]; |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
my $attr = {}; my $conf = $self->config; |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
$conf->can( 'transport_attr' ) and $attr = { %{ $conf->transport_attr } }; |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
exists $args->{transport_attr} |
112
|
|
|
|
|
|
|
and $attr = { %{ $attr }, %{ $args->{transport_attr} } }; |
113
|
|
|
|
|
|
|
exists $args->{host} and $attr->{host} = $args->{host}; |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
$attr->{host} //= 'localhost'; my $class = delete $attr->{class}; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
$class = $args->{mailer} // $class // 'SMTP'; |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
if ('+' eq substr $class, 0, 1) { $class = substr $class, 1 } |
120
|
|
|
|
|
|
|
else { $class = "Email::Sender::Transport::${class}" } |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
ensure_class_loaded $class; |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
my $mailer = $class->new( $attr ); |
125
|
|
|
|
|
|
|
my $send_args = { from => $args->{from}, to => $args->{to} }; |
126
|
|
|
|
|
|
|
my $result; |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
try { $result = $mailer->send( $args->{email}, $send_args ) } |
129
|
|
|
|
|
|
|
catch { throw $_ }; |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
$result->can( 'failure' ) and throw $result->message; |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
(blessed $result and $result->isa( 'Email::Sender::Success' )) |
134
|
|
|
|
|
|
|
or throw 'Send failed: [_1]', [ $result ]; |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
return ($result->can( 'message' ) and defined $result->message |
137
|
|
|
|
|
|
|
and length $result->message) ? $result->message : 'OK Message sent'; |
138
|
|
|
|
|
|
|
}; |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# Public methods |
141
|
|
|
|
|
|
|
sub send_email { |
142
|
13
|
|
|
13
|
1
|
48208
|
my ($self, @args) = @_; |
143
|
|
|
|
|
|
|
|
144
|
13
|
100
|
|
|
|
52
|
defined $args[ 0 ] or throw Unspecified, [ 'email args' ]; |
145
|
|
|
|
|
|
|
|
146
|
12
|
50
|
|
|
|
50
|
my $args = (is_hashref $args[ 0 ]) ? $args[ 0 ] : { @args }; |
147
|
|
|
|
|
|
|
|
148
|
12
|
|
|
|
|
90
|
$args->{email} = $_create_email->( $self, $args ); |
149
|
|
|
|
|
|
|
|
150
|
7
|
|
|
|
|
11613
|
return $_transport_email->( $self, $args ); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub try_to_send_email { |
154
|
2
|
|
|
2
|
1
|
2964
|
my ($self, @args) = @_; my $res; |
|
2
|
|
|
|
|
3
|
|
155
|
|
|
|
|
|
|
|
156
|
2
|
|
|
2
|
|
58
|
try { $res = $self->send_email( @args ) } |
157
|
2
|
|
|
1
|
|
15
|
catch { $self->log->error( $res = $_ ) }; |
|
1
|
|
|
|
|
3079
|
|
158
|
|
|
|
|
|
|
|
159
|
2
|
|
|
|
|
31
|
return $res; |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
1; |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
__END__ |