POD updates
[catagits/Catalyst-View-Email.git] / lib / Catalyst / View / Email.pm
1 package Catalyst::View::Email;
2
3 use warnings;
4 use strict;
5
6 use Class::C3;
7 use Carp;
8
9 use Email::Send;
10 use Email::MIME::Creator;
11
12 use base qw/ Catalyst::View /;
13
14 our $VERSION = '0.10';
15
16 __PACKAGE__->mk_accessors(qw/ mailer /);
17
18 =head1 NAME
19
20 Catalyst::View::Email - Send Email from Catalyst
21
22 =head1 SYNOPSIS
23
24 This module sends out emails from a stash key specified in the
25 configuration settings.
26
27 =head1 CONFIGURATION
28
29 WARNING: since version 0.10 the configuration options slightly changed!
30
31 Use the helper to create your View:
32     
33     $ script/myapp_create.pl view Email Email
34
35 In your app configuration (example in L<YAML>):
36
37     View::Email:
38         # Where to look in the stash for the email information.
39         # 'email' is the default, so you don't have to specify it.
40         stash_key: email
41         # Define the defaults for the mail
42         default:
43             # Defines the default content type (mime type).
44             # mandatory
45             content_type: text/plain
46             # Defines the default charset for every MIME part with the content
47             # type text.
48             # According to RFC2049 a MIME part without a charset should
49             # be treated as US-ASCII by the mail client.
50             # If the charset is not set it won't be set for all MIME parts
51             # without an overridden one.
52             # Default: none
53             charset: utf-8
54         # Setup how to send the email
55         # all those options are passed directly to Email::Send
56         sender:
57             mailer: SMTP
58             # mailer_args is passed directly into Email::Send 
59             mailer_args:
60                 Host:       smtp.example.com # defaults to localhost
61                 username:   username
62                 password:   password
63
64 =head1 NOTE ON SMTP
65
66 If you use SMTP and don't specify Host, it will default to localhost and
67 attempt delivery. This often means an email will sit in a queue and
68 not be delivered.
69
70 =cut
71
72 __PACKAGE__->config(
73     stash_key   => 'email',
74     default     => {
75         content_type    => 'text/plain',
76     },
77 );
78
79 =head1 SENDING EMAIL
80
81 Sending email is just filling the stash and forwarding to the view:
82
83     sub controller : Private {
84         my ( $self, $c ) = @_;
85
86         $c->stash->{email} = {
87             to      => 'jshirley@gmail.com',
88             cc      => 'abraxxa@cpan.org',
89             bcc     => [ qw/hidden@secret.com hidden2@foobar.com/ ],
90             from    => 'no-reply@foobar.com',
91             subject => 'I am a Catalyst generated email',
92             body    => 'Body Body Body',
93         };
94         
95         $c->forward( $c->view('Email') );
96     }
97
98 Alternatively you can use a more raw interface and specify the headers as
99 an array reference like it is passed to L<Email::MIME::Creator>.
100 Note that you may also mix both syntaxes if you like ours better but need to
101 specify additional header attributes.
102 The attributes are appended to the header array reference without overwriting
103 contained ones.
104
105     $c->stash->{email} = {
106         header => [
107             To      => 'jshirley@gmail.com',
108             Cc      => 'abraxxa@cpan.org',
109             Bcc     => [ qw/hidden@secret.com hidden2@foobar.com/ ],
110             From    => 'no-reply@foobar.com',
111             Subject => 'Note the capitalization differences',
112         ],
113         body => qq{Ain't got no body, and nobody cares.},
114         # Or, send parts
115         parts => [
116             Email::MIME->create(
117                 attributes => {
118                     content_type => 'text/plain',
119                     disposition  => 'attachment',
120                     charset      => 'US-ASCII',
121                 },
122                 body => qq{Got a body, but didn't get ahead.},
123             )
124         ],
125     };
126
127 =head1 HANDLING ERRORS
128
129 If the email fails to send, the view will die (throw an exception).
130 After your forward to the view, it is a good idea to check for errors:
131     
132     $c->forward( $c->view('Email') );
133     
134     if ( scalar( @{ $c->error } ) ) {
135         $c->error(0); # Reset the error condition if you need to
136         $c->response->body('Oh noes!');
137     } else {
138         $c->response->body('Email sent A-OK! (At least as far as we can tell)');
139     }
140
141 =head1 USING TEMPLATES FOR EMAIL
142
143 Now, it's no fun to just send out email using plain strings.
144 Take a look at L<Catalyst::View::Email::Template> to see how you can use your
145 favourite template engine to render the mail body.
146
147 =head1 METHODS
148
149 =over 4
150
151 =item new
152
153 Validates the base config and creates the L<Email::Send> object for later use
154 by process.
155
156 =cut
157
158 sub new {
159     my $self = shift->next::method(@_);
160
161     my $stash_key = $self->{stash_key};
162     croak "$self stash_key isn't defined!"
163         if ($stash_key eq '');
164
165     my $sender = Email::Send->new;
166
167     if ( my $mailer = $self->{sender}->{mailer} ) {
168         croak "$mailer is not supported, see Email::Send"
169             unless $sender->mailer_available($mailer);
170         $sender->mailer($mailer);
171     }
172     else {
173         # Default case, run through the most likely options first.
174         for ( qw/SMTP Sendmail Qmail/ ) {
175             $sender->mailer($_) and last if $sender->mailer_available($_);
176         }
177     }
178
179     if ( my $args = $self->{sender}->{mailer_args} ) {
180         if ( ref $args eq 'HASH' ) {
181             $sender->mailer_args([ %$args ]);
182         }
183         elsif ( ref $args eq 'ARRAY' ) {
184             $sender->mailer_args($args);
185         } else {
186             croak "Invalid mailer_args specified, check pod for Email::Send!";
187         }
188     }
189
190     $self->mailer($sender);
191
192     return $self;
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     if ( exists $self->{content_type} ) {
215         $email->{content_type} ||= $self->{content_type};
216     }
217
218     my $header  = $email->{header} || [];
219         push @$header, ('To' => delete $email->{to})
220             if $email->{to};
221         push @$header, ('Cc' => delete $email->{cc})
222             if $email->{cc};
223         push @$header, ('Bcc' => delete $email->{bcc})
224             if $email->{bcc};
225         push @$header, ('From' => delete $email->{from})
226             if $email->{from};
227         push @$header, ('Subject' => delete $email->{subject})
228             if $email->{subject};
229         push @$header, ('Content-type' => delete $email->{content_type})
230             if $email->{content_type};
231
232     my $parts = $email->{parts};
233     my $body  = $email->{body};
234    
235     unless ( $parts or $body ) {
236         croak "Can't send email without parts or body, check stash";
237     }
238
239     my %mime = ( header => $header );
240
241     if ( $parts and ref $parts eq 'ARRAY' ) {
242         $mime{parts} = $parts;
243     } else {
244         $mime{body} = $body;
245     }
246     
247     if ( $mime{attributes} and not $mime{attributes}->{charset} and
248          $self->{default}->{charset} )
249     {
250         $mime{attributes}->{charset} = $self->{default}->{charset};
251     }
252
253     my $message = $self->generate_message( $c, \%mime );
254
255     if ( $message ) {
256         my $return = $self->mailer->send($message);
257         # return is a Return::Value object, so this will stringify as the error
258         # in the case of a failure.  
259         croak "$return" if !$return;
260     } else {
261         croak "Unable to create message";
262     }
263 }
264
265 =item setup_attributes($c, $attr)
266
267 Merge attributes with the configured defaults. You can override this method to
268 return a structure to pass into L<generate_message> which subsequently
269 passes the return value of this method to Email::MIME->create under the
270 C<attributes> key.
271
272 =cut
273
274 sub setup_attributes {
275     my ( $self, $c, $attrs ) = @_;
276     
277     my $default_content_type    = $self->{default}->{content_type};
278     my $default_charset         = $self->{default}->{charset};
279
280     my $e_m_attrs = {};
281
282     if (exists $attrs->{content_type} && defined $attrs->{content_type} && $attrs->{content_type} ne '') {
283         $c->log->debug('C::V::Email uses specified content_type ' . $attrs->{content_type} . '.') if $c->debug;
284         $e_m_attrs->{content_type} = $attrs->{content_type};
285     }
286     elsif (defined $default_content_type && $default_content_type ne '') {
287         $c->log->debug("C::V::Email uses default content_type $default_content_type.") if $c->debug;
288         $e_m_attrs->{content_type} = $default_content_type;
289     }
290    
291     if (exists $attrs->{charset} && defined $attrs->{charset} && $attrs->{charset} ne '') {
292         $e_m_attrs->{charset} = $attrs->{charset};
293     }
294     elsif (defined $default_charset && $default_charset ne '') {
295         $e_m_attrs->{charset} = $default_charset;
296     }
297
298     return $e_m_attrs;
299 }
300
301 =item generate_message($c, $attr)
302
303 Generate a message part, which should be an L<Email::MIME> object and return it.
304
305 Takes the attributes, merges with the defaults as necessary and returns a
306 message object.
307
308 =cut
309
310 sub generate_message {
311     my ( $self, $c, $attr ) = @_;
312
313     # setup the attributes (merge with defaults)
314     $attr->{attributes} = $self->setup_attributes($c, $attr->{attributes});
315     return Email::MIME->create(%$attr);
316 }
317
318 =back
319
320 =head1 SEE ALSO
321
322 =head2 L<Catalyst::View::Email::Template> - Send fancy template emails with Cat
323
324 =head2 L<Catalyst::Manual> - The Catalyst Manual
325
326 =head2 L<Catalyst::Manual::Cookbook> - The Catalyst Cookbook
327
328 =head1 AUTHORS
329
330 J. Shirley <jshirley@gmail.com>
331
332 Alexander Hartmaier <abraxxa@cpan.org>
333
334 =head1 CONTRIBUTORS
335
336 (Thanks!)
337
338 Matt S Trout
339
340 Daniel Westermann-Clark
341
342 Simon Elliott <cpan@browsing.co.uk>
343
344 Roman Filippov
345
346 =head1 LICENSE
347
348 This library is free software, you can redistribute it and/or modify it under
349 the same terms as Perl itself.
350
351 =cut
352
353 1;