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