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