upped version
[catagits/Catalyst-View-Email.git] / lib / Catalyst / View / Email.pm
1 package Catalyst::View::Email;
2
3 use Moose;
4 use Carp;
5
6 use Encode qw(encode decode);
7 use Email::Sender::Simple qw/ sendmail /;
8 use Email::MIME::Creator;
9 extends 'Catalyst::View';
10
11 our $VERSION = '0.21';
12 $VERSION = eval $VERSION;
13
14 has 'mailer' => (
15     is      => 'rw',
16     isa     => 'Str',
17     lazy    => 1,
18     default => sub { "sendmail" }
19 );
20
21 has '_mailer_obj' => (
22     is      => 'rw',
23     isa     => 'Email::Sender::Transport',
24     lazy    => 1,
25     builder => '_build_mailer_obj',
26 );
27
28 has 'stash_key' => (
29     is      => 'rw',
30     isa     => 'Str',
31     lazy    => 1,
32     default => sub { "email" }
33 );
34
35 has 'default' => (
36     is      => 'rw',
37     isa     => 'HashRef',
38     default => sub { { content_type => 'text/plain' } },
39     lazy    => 1,
40 );
41
42 has 'sender' => (
43     is      => 'rw',
44     isa     => 'HashRef',
45     lazy    => 1,
46     default => sub { { mailer => shift->mailer } }
47 );
48
49 has 'content_type' => (
50     is      => 'rw',
51         isa     => 'Str',
52         default => sub { shift->default->{content_type} },
53         lazy    => 1,
54 );
55
56 =head1 NAME
57
58 Catalyst::View::Email - Send Email from Catalyst
59
60 =head1 VERSION
61
62 version 0.19
63
64 =head1 SYNOPSIS
65
66 This module sends out emails from a stash key specified in the
67 configuration settings.
68
69 =head1 CONFIGURATION
70
71 WARNING: since version 0.10 the configuration options slightly changed!
72
73 Use the helper to create your View:
74     
75     $ script/myapp_create.pl view Email Email
76
77 In your app configuration:
78
79     __PACKAGE__->config(
80         'View::Email' => {
81             # Where to look in the stash for the email information.
82             # 'email' is the default, so you don't have to specify it.
83             stash_key => 'email',
84             # Define the defaults for the mail
85             default => {
86                 # Defines the default content type (mime type). Mandatory
87                 content_type => 'text/plain',
88                 # Defines the default charset for every MIME part with the 
89                 # content type text.
90                 # According to RFC2049 a MIME part without a charset should
91                 # be treated as US-ASCII by the mail client.
92                 # If the charset is not set it won't be set for all MIME parts
93                 # without an overridden one.
94                 # Default: none
95                 charset => 'utf-8'
96             },
97             # Setup how to send the email
98             # all those options are passed directly to Email::Send
99             sender => {
100                 # if mailer doesn't start with Email::Sender::Transport::,
101                 # then this is prepended.
102                 mailer => 'SMTP',
103                 # mailer_args is passed directly into Email::Send 
104                 mailer_args => {
105                     host     => 'smtp.example.com', # defaults to localhost
106                     username => 'username',
107                     password => 'password',
108             }
109           }
110         }
111     );
112
113 =head1 NOTE ON SMTP
114
115 If you use SMTP and don't specify host, it will default to localhost and
116 attempt delivery. This often means an email will sit in a queue and
117 not be delivered.
118
119 =cut
120
121 =head1 SENDING EMAIL
122
123 Sending email is just filling the stash and forwarding to the view:
124
125     sub controller : Private {
126         my ( $self, $c ) = @_;
127
128         $c->stash->{email} = {
129             to      => 'jshirley@gmail.com',
130             cc      => 'abraxxa@cpan.org',
131             bcc     => join ',', qw/hidden@secret.com hidden2@foobar.com/,
132             from    => 'no-reply@foobar.com',
133             subject => 'I am a Catalyst generated email',
134             body    => 'Body Body Body',
135         };
136         
137         $c->forward( $c->view('Email') );
138     }
139
140 Alternatively you can use a more raw interface and specify the headers as
141 an array reference like it is passed to L<Email::MIME::Creator>.
142 Note that you may also mix both syntaxes if you like ours better but need to
143 specify additional header attributes.
144 The attributes are appended to the header array reference without overwriting
145 contained ones.
146
147     $c->stash->{email} = {
148         header => [
149             To      => 'jshirley@gmail.com',
150             Cc      => 'abraxxa@cpan.org',
151             Bcc     => join ',', qw/hidden@secret.com hidden2@foobar.com/,
152             From    => 'no-reply@foobar.com',
153             Subject => 'Note the capitalization differences',
154         ],
155         body => qq{Ain't got no body, and nobody cares.},
156         # Or, send parts
157         parts => [
158             Email::MIME->create(
159                 attributes => {
160                     content_type => 'text/plain',
161                     disposition  => 'attachment',
162                     charset      => 'US-ASCII',
163                 },
164                 body => qq{Got a body, but didn't get ahead.},
165             )
166         ],
167     };
168
169 =head1 HANDLING ERRORS
170
171 If the email fails to send, the view will die (throw an exception).
172 After your forward to the view, it is a good idea to check for errors:
173     
174     $c->forward( $c->view('Email') );
175     
176     if ( scalar( @{ $c->error } ) ) {
177         $c->error(0); # Reset the error condition if you need to
178         $c->response->body('Oh noes!');
179     } else {
180         $c->response->body('Email sent A-OK! (At least as far as we can tell)');
181     }
182
183 =head1 USING TEMPLATES FOR EMAIL
184
185 Now, it's no fun to just send out email using plain strings.
186 Take a look at L<Catalyst::View::Email::Template> to see how you can use your
187 favourite template engine to render the mail body.
188
189 =head1 METHODS
190
191 =over 4
192
193 =item new
194
195 Validates the base config and creates the L<Email::Send> object for later use
196 by process.
197
198 =cut
199
200 sub BUILD {
201     my $self = shift;
202
203     my $stash_key = $self->stash_key;
204     croak "$self stash_key isn't defined!"
205       if ( $stash_key eq '' );
206
207 }
208
209 sub _build_mailer_obj {
210   my ($self) = @_;
211   my $transport_class = ucfirst $self->sender->{mailer};
212
213   # borrowed from Email::Sender::Simple -- apeiron, 2010-01-26 
214   if ($transport_class !~ /^Email::Sender::Transport::/) {
215     $transport_class = "Email::Sender::Transport::$transport_class";
216   }
217
218   Class::MOP::load_class($transport_class);
219
220   return $transport_class->new($self->sender->{mailer_args} || {});
221 }
222
223 =item process($c)
224
225 The process method does the actual processing when the view is dispatched to.
226
227 This method sets up the email parts and hands off to L<Email::Send> to handle
228 the actual email delivery.
229
230 =cut
231
232 sub process {
233     my ( $self, $c ) = @_;
234
235     croak "Unable to send mail, bad mail configuration"
236       unless $self->sender->{mailer};
237
238     my $email = $c->stash->{ $self->stash_key };
239     croak "Can't send email without a valid email structure"
240       unless $email;
241
242     # Default content type
243     if ( $self->content_type and not $email->{content_type} ) {
244         $email->{content_type} = $self->content_type;
245     }
246
247     my $header = $email->{header} || [];
248     push @$header, ( 'To' => delete $email->{to} )
249       if $email->{to};
250     push @$header, ( 'Cc' => delete $email->{cc} )
251       if $email->{cc};
252     push @$header, ( 'Bcc' => delete $email->{bcc} )
253       if $email->{bcc};
254     push @$header, ( 'From' => delete $email->{from} )
255       if $email->{from};
256     push @$header,
257       ( 'Subject' => Encode::encode( 'MIME-Header', delete $email->{subject} ) )
258       if $email->{subject};
259     push @$header, ( 'Content-type' => $email->{content_type} )
260       if $email->{content_type};
261
262     my $parts = $email->{parts};
263     my $body  = $email->{body};
264
265     unless ( $parts or $body ) {
266         croak "Can't send email without parts or body, check stash";
267     }
268
269     my %mime = ( header => $header, attributes => {} );
270
271     if ( $parts and ref $parts eq 'ARRAY' ) {
272         $mime{parts} = $parts;
273     }
274     else {
275         $mime{body} = $body;
276     }
277
278     $mime{attributes}->{content_type} = $email->{content_type}
279       if $email->{content_type};
280     if (    $mime{attributes}
281         and not $mime{attributes}->{charset}
282         and $self->{default}->{charset} )
283     {
284         $mime{attributes}->{charset} = $self->{default}->{charset};
285     }
286
287     my $message = $self->generate_message( $c, \%mime );
288
289     if ($message) {
290         my $return = sendmail( $message, { transport => $self->_mailer_obj } );
291
292         # return is a Return::Value object, so this will stringify as the error
293         # in the case of a failure.
294         croak "$return" if !$return;
295     }
296     else {
297         croak "Unable to create message";
298     }
299 }
300
301 =item setup_attributes($c, $attr)
302
303 Merge attributes with the configured defaults. You can override this method to
304 return a structure to pass into L<generate_message> which subsequently
305 passes the return value of this method to Email::MIME->create under the
306 C<attributes> key.
307
308 =cut
309
310 sub setup_attributes {
311     my ( $self, $c, $attrs ) = @_;
312
313     my $default_content_type = $self->default->{content_type};
314     my $default_charset      = $self->default->{charset};
315
316     my $e_m_attrs = {};
317
318     if (   exists $attrs->{content_type}
319         && defined $attrs->{content_type}
320         && $attrs->{content_type} ne '' )
321     {
322         $c->log->debug( 'C::V::Email uses specified content_type '
323               . $attrs->{content_type}
324               . '.' )
325           if $c->debug;
326         $e_m_attrs->{content_type} = $attrs->{content_type};
327     }
328     elsif ( defined $default_content_type && $default_content_type ne '' ) {
329         $c->log->debug(
330             "C::V::Email uses default content_type $default_content_type.")
331           if $c->debug;
332         $e_m_attrs->{content_type} = $default_content_type;
333     }
334
335     if (   exists $attrs->{charset}
336         && defined $attrs->{charset}
337         && $attrs->{charset} ne '' )
338     {
339         $e_m_attrs->{charset} = $attrs->{charset};
340     }
341     elsif ( defined $default_charset && $default_charset ne '' ) {
342         $e_m_attrs->{charset} = $default_charset;
343     }
344
345     return $e_m_attrs;
346 }
347
348 =item generate_message($c, $attr)
349
350 Generate a message part, which should be an L<Email::MIME> object and return it.
351
352 Takes the attributes, merges with the defaults as necessary and returns a
353 message object.
354
355 =cut
356
357 sub generate_message {
358     my ( $self, $c, $attr ) = @_;
359
360     # setup the attributes (merge with defaultis)
361         $attr->{attributes} = $self->setup_attributes($c, $attr->{attributes});
362     Email::MIME->create(
363             %$attr
364         );
365 }
366
367 =back
368
369
370 =head1 TROUBLESHOOTING
371
372 As with most things computer related, things break.  Email even more so.  
373 Typically any errors are going to come from using SMTP as your sending method,
374 which means that if you are having trouble the first place to look is at
375 L<Email::Send::SMTP>.  This module is just a wrapper for L<Email::Send>,
376 so if you get an error on sending, it is likely from there anyway.
377
378 If you are using SMTP and have troubles sending, whether it is authentication
379 or a very bland "Can't send" message, make sure that you have L<Net::SMTP> and,
380 if applicable, L<Net::SMTP::SSL> installed.
381
382 It is very simple to check that you can connect via L<Net::SMTP>, and if you
383 do have sending errors the first thing to do is to write a simple script
384 that attempts to connect.  If it works, it is probably something in your
385 configuration so double check there.  If it doesn't, well, keep modifying
386 the script and/or your mail server configuration until it does!
387
388 =head1 SEE ALSO
389
390 =head2 L<Catalyst::View::Email::Template> - Send fancy template emails with Cat
391
392 =head2 L<Catalyst::Manual> - The Catalyst Manual
393
394 =head2 L<Catalyst::Manual::Cookbook> - The Catalyst Cookbook
395
396 =head1 AUTHORS
397
398 J. Shirley <jshirley@gmail.com>
399
400 Alexander Hartmaier <abraxxa@cpan.org>
401
402 =head1 CONTRIBUTORS
403
404 (Thanks!)
405
406 Matt S Trout
407
408 Daniel Westermann-Clark
409
410 Simon Elliott <cpan@browsing.co.uk>
411
412 Roman Filippov
413
414 Lance Brown <lance@bearcircle.net>
415
416 Devin Austin <dhoss@cpan.org>
417
418 Chris Nehren <apeiron@cpan.org>
419
420 =head1 COPYRIGHT
421
422 Copyright (c) 2007 - 2009
423 the Catalyst::View::Email L</AUTHORS> and L</CONTRIBUTORS>
424 as listed above.
425
426 =head1 LICENSE
427
428 This library is free software, you can redistribute it and/or modify it under
429 the same terms as Perl itself.
430
431 =cut
432
433 1;