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