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