File Coverage

blib/lib/App/Basis/Email.pm
Criterion Covered Total %
statement 57 78 73.0
branch 11 28 39.2
condition 2 9 22.2
subroutine 13 15 86.6
pod 1 2 50.0
total 84 132 63.6


line stmt bran cond sub pod time code
1             # ABSTRACT: Simple email sending, nothing special
2              
3             =head1 NAME
4              
5             App::Basis::Email
6              
7             =head1 SYNOPSIS
8              
9             use Text::Markdown qw(markdown);
10             use App::Basis::Email ;
11              
12             my $markdown = <
13             # Basic Markdown
14              
15             ![BBC Logo](http://static.bbci.co.uk/frameworks/barlesque/2.60.6/orb/4/img/bbc-blocks-light.png)
16              
17             That was an inlined image
18              
19             ## level2 header
20              
21             * bullet
22             * sub-bullet
23              
24             ### level3 header
25              
26             EOD
27             my $html = markdown($markdown);
28              
29             my $mail = App::Basis::Email->new( hostname => 'my.email.server', port => 25 ) ;
30             my $status = $mail->send(
31             from => 'fred@fred.test.fred',
32             to => 'fred@fred.test.fred',
33             subject => 'test HTML email, with inline images',
34             html => $html
35             );
36              
37             =head1 DESCRIPTION
38            
39             Sending email should be simple, sending formatted email should be simple too.
40             I just want to be able to say send this thing via this process.
41              
42             This module provides that, a way to simply send email (plain/html or markdown) via
43             either a SMTP or sendmail target.
44              
45             Obviously I do nothing new, just wrap around existing modules, to make life simple.
46              
47             =head1 AUTHOR
48              
49             kevin mulholland
50              
51             =head1 Notes
52              
53             if you want templating then do it outside of this module and pass the formatted
54             HTML/markdown in
55              
56             =head1 See Also
57              
58             To create email I use L, you may need to force this to
59             install it as there is a slight test bug
60             To send email I use L with L and L
61             Markdown processing is done with L
62              
63             =over 4
64              
65             =cut
66              
67             package App::Basis::Email;
68             $App::Basis::Email::VERSION = '0.3';
69 2     2   223878 use 5.010;
  2         8  
  2         82  
70 2     2   11 use warnings;
  2         3  
  2         49  
71 2     2   10 use strict;
  2         8  
  2         76  
72 2     2   1662 use Moo;
  2         33631  
  2         13  
73 2     2   3943 use Try::Tiny;
  2         4  
  2         161  
74              
75 2     2   1914 use Email::Sender::Simple qw(sendmail);
  2         585201  
  2         17  
76 2     2   2768 use Email::Sender::Transport::SMTP qw();
  2         31803  
  2         134  
77 2     2   1996 use Email::Sender::Transport::Sendmail;
  2         6433  
  2         67  
78              
79 2     2   1908 use Email::MIME::CreateHTML;
  2         321463  
  2         123  
80 2     2   26 use Text::Markdown 'markdown';
  2         4  
  2         125  
81 2     2   2403 use HTML::Restrict;
  2         292763  
  2         1930  
82              
83             # ----------------------------------------------------------------------------
84              
85             # what host name are we connecting to, defaults to localhost
86             has host => ( is => 'ro', );
87              
88             # on what port
89             has port => (
90             is => 'ro',
91             default => sub { 25 },
92             );
93              
94             # do we want to use SSL
95             has ssl => (
96             is => 'ro',
97             default => sub { 0 },
98             );
99              
100             # SSL needs a user
101             has user => (
102             is => 'ro',
103             default => sub { '' },
104             );
105             # SSL user needs a password
106             has passwd => (
107             is => 'ro',
108             default => sub { '' },
109             );
110              
111             # how should we send things, either SMTP or Sendmail (default)
112             has transport => (
113             is => 'ro',
114             writer => '_set_transport'
115             );
116              
117             # if using sendmail having the path to the binary would help
118             has sendmail_path => ( is => 'ro' );
119              
120             # we want a testing mode that will not send email, so that we can get output
121             # and use it for validation in our test scripts
122             has testing => ( is => 'ro' );
123              
124             # ----------------------------------------------------------------------------
125             has sender => (
126             is => 'ro',
127             init_arg => undef, # dont allow setting in constructor
128             writer => '_set_sender'
129             );
130              
131             # ----------------------------------------------------------------------------
132              
133             =item new
134              
135             Create a new instance of the email
136              
137             my $mail = App::Basis::Email->new( host => "email.server.fred", port => 25 );
138              
139             B
140             host ip address or hotsname of your SMTP server
141             port optional port number for SMTP, defaults to 25
142             ssl use SSL mode
143             user user for ssl
144             passwd password for ssl
145             testing flag to show testing mode, prevents sending of email
146              
147             =cut
148              
149             sub BUILD {
150 4     4 0 25 my $self = shift;
151 4         8 my $sender;
152 4         18 my $transport = $self->transport;
153              
154 4 100       26 $transport = 'SMTP' if ( $self->host );
155              
156 4 50       16 die "You need either host or transport Sendmail defined" if ( !$transport );
157 4 50 0     27 die "You need username/password for SSL" if ( $self->ssl && !( $self->user && $self->passwd ) );
      33        
158              
159             # its sendmail or SMTP
160 4 100       21 if ( $transport =~ /sendmail/i ) {
161 2 50       13 die "sendmail_path should be passed to new when using transport => 'sendmail" if( !$self->sendmail_path) ;
162 2         26 $sender = Email::Sender::Transport::Sendmail->new( { sendmail => $self->sendmail_path } );
163             }
164             else {
165 2         53 $sender = Email::Sender::Transport::SMTP->new(
166             {
167             host => $self->host,
168             port => $self->port,
169             ssl => $self->ssl,
170             sasl_username => $self->user,
171             sasl_password => $self->passwd
172             }
173             );
174             }
175             # make sure we set this, as it can be tested for in our test code
176 4         14299 $self->_set_transport($transport);
177             # this too
178 4         130 $self->_set_sender($sender);
179             }
180              
181             # ----------------------------------------------------------------------------
182              
183             =item send
184              
185             send the required email
186              
187             my $mail = App::Basis::Email->new( hostname => 'my.email.server', port => 25 ) ;
188             my $status = $mail->send(
189             from => 'fred@fred.test.fred',
190             to => 'fred@fred.test.fred',
191             subject => 'test HTML email, with inline images',
192             html => $html
193             );
194              
195             Any data that is in the hash is passed to the server, though some may be re-interpreted
196             as mentioned in the DESCRIPTION
197              
198             B
199             to email address to (can be array of email addresses)
200             cc email cc list (can be array of email addresses)
201             from email address from
202             subject subject for the email
203             text teset message to send, for email clients that do not do html
204             html html message to send
205             markdown markdown message to send, converted to html and replaces it
206             css_file link to a css file to use for HTML/markdown files
207              
208             B
209             status - true = Sent, false = Failed (string of email message if testing flag used)
210              
211             =cut
212              
213             sub send {
214 2     2 1 2213 my $self = shift;
215 2         18 my %params = @_;
216 2         5 my $status = 0;
217 2         4 my $to_str;
218              
219             # if we have markdown, then this replaces the HTML
220 2 50       12 if ( $params{markdown} ) {
221 0         0 $params{html} = markdown( $params{markdown} );
222             }
223             # if we do markdown or HTML and the user has not supplied alternative text
224             # then we should strip all the HTML formatting from the html text and
225             # use that
226 2 50 33     24 if ( $params{html} && !$params{text} ) {
227              
228 2         26 my $hr = HTML::Restrict->new();
229              
230             # use default rules to start with (strip away all HTML)
231 2         13806 $params{text} = $hr->process( $params{html} );
232             }
233 2 50       16615 if ( !$params{html} ) {
234 0         0 $params{html} = "

$params{text}

";
235             }
236              
237 2 50       38 if ( ref( $params{to} ) eq 'ARRAY' ) {
238 0         0 $to_str = join( ', ', @{ $params{to} } );
  0         0  
239             }
240             else {
241 2         6 $to_str = $params{to};
242             }
243              
244 2         38 my $email = Email::MIME->create_html(
245             header => [
246             From => $params{from},
247             To => $to_str,
248             Subject => $params{subject},
249             ],
250             body => $params{html},
251             text_body => $params{text},
252             inline_css => 1
253             );
254              
255 0 0         if ( ref( $params{to} ) eq 'ARRAY' ) {
256 0           $email->header_str_set( To => @{ $params{to} } );
  0            
257             }
258              
259 0 0         if ( $params{cc} ) {
260 0 0         if ( ref( $params{cc} eq 'ARRAY' ) ) {
261 0           $email->header_str_set( CC => @{ $params{cc} } );
  0            
262             }
263             else {
264 0           $email->header_str_set( CC => $params{cc} );
265             }
266             }
267              
268 0           my $success;
269 0 0         if ( $self->testing ) {
270             # when we are testing we will not attempt the send
271             # but we will return what would have been sent
272             # we must assume that the send aspect works as this is built on
273             # other peoples code and considered sound.
274             # We don't do anything particularly fancy with it.
275 0           return $email->as_string;
276             }
277             else {
278             try {
279 0     0     $success = sendmail(
280             $email,
281             {
282             # from => $params{from},
283             transport => $self->sender
284             }
285             );
286             }
287             catch {
288 0     0     warn "email sending failed: $_";
289 0           };
290             }
291              
292 0 0         if ($success) {
293 0           $status = 1;
294             }
295 0           return $status;
296             }
297              
298             # ----------------------------------------------------------------------------
299              
300             =back
301              
302             =cut
303              
304             # ----------------------------------------------------------------------------
305              
306             1;