bb304cfb41906f1bce7806d91010cbfbe8785234
[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 sub process {
177     my ( $self, $c ) = @_;
178
179     croak "Unable to send mail, bad mail configuration"
180         unless $self->mailer;
181
182     my $email  = $c->stash->{$self->{stash_key}};
183     croak "Can't send email without a valid email structure"
184         unless $email;
185
186     if ( exists $self->{content_type} ) {
187         $email->{content_type} ||= $self->{content_type};
188     }
189
190     my $header  = $email->{header} || [];
191         push @$header, ('To' => delete $email->{to})
192             if $email->{to};
193         push @$header, ('Cc' => delete $email->{cc})
194             if $email->{cc};
195         push @$header, ('Bcc' => delete $email->{bcc})
196             if $email->{bcc};
197         push @$header, ('From' => delete $email->{from})
198             if $email->{from};
199         push @$header, ('Subject' => delete $email->{subject})
200             if $email->{subject};
201         push @$header, ('Content-type' => delete $email->{content_type})
202             if $email->{content_type};
203
204     my $parts = $email->{parts};
205     my $body  = $email->{body};
206    
207     unless ( $parts or $body ) {
208         croak "Can't send email without parts or body, check stash";
209     }
210
211     my %mime = ( header => $header );
212
213     if ( $parts and ref $parts eq 'ARRAY' ) {
214         $mime{parts} = $parts;
215     } else {
216         $mime{body} = $body;
217     }
218     
219     if ( $mime{attributes} and not $mime{attributes}->{charset} and
220          $self->{default}->{charset} )
221     {
222         $mime{attributes}->{charset} = $self->{default}->{charset};
223     }
224
225     my $message = $self->generate_message( $c, \%mime );
226
227     #my $message = Email::MIME->create(%mime);
228
229     if ( $message ) {
230         my $return = $self->mailer->send($message);
231         croak "$return" if !$return;
232     } else {
233         croak "Unable to create message";
234     }
235 }
236
237 sub setup_attributes {
238     my ( $self, $c, $attrs ) = @_;
239     
240     my $default_content_type    = $self->{default}->{content_type};
241     my $default_charset         = $self->{default}->{charset};
242
243     my $e_m_attrs = {};
244
245     if (exists $attrs->{content_type} && defined $attrs->{content_type} && $attrs->{content_type} ne '') {
246         $c->log->debug('C::V::Email uses specified content_type ' . $attrs->{content_type} . '.') if $c->debug;
247         $e_m_attrs->{content_type} = $attrs->{content_type};
248     }
249     elsif (defined $default_content_type && $default_content_type ne '') {
250         $c->log->debug("C::V::Email uses default content_type $default_content_type.") if $c->debug;
251         $e_m_attrs->{content_type} = $default_content_type;
252     }
253    
254     if (exists $attrs->{charset} && defined $attrs->{charset} && $attrs->{charset} ne '') {
255         $e_m_attrs->{charset} = $attrs->{charset};
256     }
257     elsif (defined $default_charset && $default_charset ne '') {
258         $e_m_attrs->{charset} = $default_charset;
259     }
260
261     return $e_m_attrs;
262 }
263
264 sub generate_message {
265     my ( $self, $c, $attr ) = @_;
266
267     # setup the attributes (merge with defaults)
268     $attr->{attributes} = $self->setup_attributes($c, $attr->{attributes});
269     return Email::MIME->create(%$attr);
270 }
271
272 =head1 SEE ALSO
273
274 =head2 L<Catalyst::View::Email::Template> - Send fancy template emails with Cat
275
276 =head2 L<Catalyst::Manual> - The Catalyst Manual
277
278 =head2 L<Catalyst::Manual::Cookbook> - The Catalyst Cookbook
279
280 =head1 AUTHORS
281
282 J. Shirley <jshirley@gmail.com>
283
284 =head1 CONTRIBUTORS
285
286 (Thanks!)
287
288 Matt S Trout
289
290 Daniel Westermann-Clark
291
292 Simon Elliott <cpan@browsing.co.uk>
293
294 Roman Filippov
295
296 Alexander Hartmaier <alex_hartmaier@hotmail.com>
297
298 =head1 LICENSE
299
300 This library is free software, you can redistribute it and/or modify it under
301 the same terms as Perl itself.
302
303 =cut
304
305 1;