bumped version
[catagits/Catalyst-View-Email.git] / lib / Catalyst / View / Email / Template.pm
CommitLineData
529915ab 1package Catalyst::View::Email::Template;
2
ce1977b0 3use Moose;
529915ab 4use Carp;
ea115f9b 5use Scalar::Util qw/ blessed /;
ce1977b0 6extends 'Catalyst::View::Email';
529915ab 7
2a0bb234 8our $VERSION = '0.33';
9ff9161d 9$VERSION = eval $VERSION;
529915ab 10=head1 NAME
11
12Catalyst::View::Email::Template - Send Templated Email from Catalyst
13
14=head1 SYNOPSIS
15
4a44bcd3 16Sends templated mail, based upon your default view. It captures the output
529915ab 17of the rendering path, slurps in based on mime-types and assembles a multi-part
4a44bcd3 18email using L<Email::MIME::Creator> and sends it out.
529915ab 19
ea115f9b 20=head1 CONFIGURATION
21
4a44bcd3 22WARNING: since version 0.10 the configuration options slightly changed!
23
24Use the helper to create your view:
ea115f9b 25
26 $ script/myapp_create.pl view Email::Template Email::Template
27
4a44bcd3 28For basic configuration look at L<Catalyst::View::Email/CONFIGURATION>.
29
ea115f9b 30In your app configuration (example in L<YAML>):
529915ab 31
32 View::Email::Template:
529915ab 33 # Optional prefix to look somewhere under the existing configured
ea115f9b 34 # template paths.
35 # Default: none
529915ab 36 template_prefix: email
06afcdbc 37 # Define the defaults for the mail
38 default:
ea115f9b 39 # Defines the default view used to render the templates.
40 # If none is specified neither here nor in the stash
41 # Catalysts default view is used.
42 # Warning: if you don't tell Catalyst explicit which of your views should
43 # be its default one, C::V::Email::Template may choose the wrong one!
06afcdbc 44 view: TT
529915ab 45
46=head1 SENDING EMAIL
47
4a44bcd3 48Sending email works just like for L<Catalyst::View::Email> but by specifying
49the template instead of the body and forwarding to your Email::Template view:
50
51 sub controller : Private {
52 my ( $self, $c ) = @_;
53
54 $c->stash->{email} = {
55 to => 'jshirley@gmail.com',
56 cc => 'abraxxa@cpan.org',
4a44bcd3 57 from => 'no-reply@foobar.com',
58 subject => 'I am a Catalyst generated email',
59 template => 'test.tt',
ab4326b4 60 content_type => 'multipart/alternative'
4a44bcd3 61 };
62
63 $c->forward( $c->view('Email::Template') );
64 }
529915ab 65
06afcdbc 66Alternatively if you want more control over your templates you can use the following idiom
beda8c31 67to override the defaults. If charset and encoding given, the body become properly encoded.
12c85b56 68
69 templates => [
06afcdbc 70 {
71 template => 'email/test.html.tt',
72 content_type => 'text/html',
ea115f9b 73 charset => 'utf-8',
beda8c31 74 encoding => 'quoted-printable',
06afcdbc 75 view => 'TT',
76 },
77 {
78 template => 'email/test.plain.mason',
79 content_type => 'text/plain',
ea115f9b 80 charset => 'utf-8',
beda8c31 81 encoding => 'quoted-printable',
06afcdbc 82 view => 'Mason',
83 }
12c85b56 84 ]
85
86
beda8c31 87
4a44bcd3 88=head1 HANDLING ERRORS
89
90See L<Catalyst::View::Email/HANDLING ERRORS>.
529915ab 91
92=cut
93
06afcdbc 94# here the defaults of Catalyst::View::Email are extended by the additional
95# ones Template.pm needs.
96
ce1977b0 97has 'stash_key' => (
98 is => 'rw',
99 isa => 'Str',
100 default => sub { "email" },
101 lazy => 1,
529915ab 102);
103
ce1977b0 104has 'template_prefix' => (
105 is => 'rw',
106 isa => 'Str',
107 default => sub { '' },
108 lazy => 1,
109);
110
111has 'default' => (
112 is => 'rw',
113 isa => 'HashRef',
114 default => sub {
115 {
116 view => 'TT',
117 content_type => 'text/html',
118 };
119 },
120 lazy => 1,
121);
529915ab 122
123# This view hitches into your default view and will call the render function
124# on the templates provided. This means that you have a layer of abstraction
125# and you aren't required to modify your templates based on your desired engine
126# (Template Toolkit or Mason, for example). As long as the view adequately
127# supports ->render, all things are good. Mason, and others, are not good.
128
129#
130# The path here is to check configuration for the template root, and then
131# proceed to call render on the subsequent templates and stuff each one
132# into an Email::MIME container. The mime-type will be stupidly guessed with
133# the subdir on the template.
134#
529915ab 135
06afcdbc 136# Set it up so if you have multiple parts, they're alternatives.
137# This is on the top-level message, not the individual parts.
138#multipart/alternative
529915ab 139
06afcdbc 140sub _validate_view {
ce1977b0 141 my ( $self, $view ) = @_;
142
4a44bcd3 143 croak "C::V::Email::Template's configured view '$view' isn't an object!"
ce1977b0 144 unless ( blessed($view) );
06afcdbc 145
ce1977b0 146 croak
147 "C::V::Email::Template's configured view '$view' isn't an Catalyst::View!"
148 unless ( $view->isa('Catalyst::View') );
06afcdbc 149
ce1977b0 150 croak
151"C::V::Email::Template's configured view '$view' doesn't have a render method!"
152 unless ( $view->can('render') );
06afcdbc 153}
529915ab 154
4a44bcd3 155=head1 METHODS
156
157=over 4
11a0bf18 158
4a44bcd3 159=item generate_part
160
161Generates a MIME part to include in the email. Since the email is template based
11a0bf18 162every template piece is a separate part that is included in the email.
163
164=cut
165
43090696 166sub generate_part {
ce1977b0 167 my ( $self, $c, $attrs ) = @_;
d0e11256 168
ce1977b0 169 my $template_prefix = $self->template_prefix;
170 my $default_view = $self->default->{view};
171 my $default_content_type = $self->default->{content_type};
beda8c31 172 my $default_charset = $self->default->{charset};
ea115f9b 173
ea115f9b 174 my $view;
ce1977b0 175
ea115f9b 176 # use the view specified for the email part
ce1977b0 177 if ( exists $attrs->{view}
178 && defined $attrs->{view}
179 && $attrs->{view} ne '' )
180 {
181 $view = $c->view( $attrs->{view} );
182 $c->log->debug(
183 "C::V::Email::Template uses specified view $view for rendering.")
184 if $c->debug;
ea115f9b 185 }
ce1977b0 186
ea115f9b 187 # if none specified use the configured default view
188 elsif ($default_view) {
189 $view = $c->view($default_view);
ce1977b0 190 $c->log->debug(
191 "C::V::Email::Template uses default view $view for rendering.")
192 if $c->debug;
ea115f9b 193 }
ce1977b0 194
ea115f9b 195 # else fallback to Catalysts default view
196 else {
197 $view = $c->view;
ce1977b0 198 $c->log->debug(
199"C::V::Email::Template uses Catalysts default view $view for rendering."
200 ) if $c->debug;
ea115f9b 201 }
06afcdbc 202
06afcdbc 203 # validate the per template view
204 $self->_validate_view($view);
ce1977b0 205
06afcdbc 206 # prefix with template_prefix if configured
ce1977b0 207 my $template =
208 $template_prefix ne ''
209 ? join( '/', $template_prefix, $attrs->{template} )
210 : $attrs->{template};
211
43090696 212 # setup the attributes (merge with defaults)
ce1977b0 213 my $e_m_attrs = $self->SUPER::setup_attributes( $c, $attrs );
ea115f9b 214
06afcdbc 215 # render the email part
ce1977b0 216 my $output = $view->render(
217 $c,
218 $template,
219 {
220 content_type => $e_m_attrs->{content_type},
221 stash_key => $self->stash_key,
1e331578 222 %{$c->stash},
ce1977b0 223 }
224 );
43090696 225 if ( ref $output ) {
226 croak $output->can('as_string') ? $output->as_string : $output;
529915ab 227 }
43090696 228
beda8c31 229 if ( exists $e_m_attrs->{encoding}
230 && defined $e_m_attrs->{encoding}
231 && exists $e_m_attrs->{charset}
232 && defined $e_m_attrs->{charset} ) {
233
234 return Email::MIME->create(
235 attributes => $e_m_attrs,
236 body_str => $output,
237 );
238
239 } else {
240
241 return Email::MIME->create(
242 attributes => $e_m_attrs,
243 body => $output,
244 );
245 }
06afcdbc 246}
529915ab 247
4a44bcd3 248=item process
11a0bf18 249
4a44bcd3 250The process method is called when the view is dispatched to. This creates the
11a0bf18 251multipart message and then sends the message contents off to
4a44bcd3 252L<Catalyst::View::Email> for processing, which in turn hands off to
54fe3544 253L<Email::Sender::Simple>.
11a0bf18 254
255=cut
256
ce1977b0 257around 'process' => sub {
258 my ( $orig, $self, $c, @args ) = @_;
259 my $stash_key = $self->stash_key;
cce24d41 260 return $self->$orig( $c, @args )
ce1977b0 261 unless $c->stash->{$stash_key}->{template}
262 or $c->stash->{$stash_key}->{templates};
8b10ee55 263
06afcdbc 264 # in case of the simple api only one
ce1977b0 265 my @parts = ();
12c85b56 266
06afcdbc 267 # now find out if the single or multipart api was used
268 # prefer the multipart one
ce1977b0 269
06afcdbc 270 # multipart api
ce1977b0 271 if ( $c->stash->{$stash_key}->{templates}
06afcdbc 272 && ref $c->stash->{$stash_key}->{templates} eq 'ARRAY'
ce1977b0 273 && ref $c->stash->{$stash_key}->{templates}[0] eq 'HASH' )
274 {
275
06afcdbc 276 # loop through all parts of the mail
ce1977b0 277 foreach my $part ( @{ $c->stash->{$stash_key}->{templates} } ) {
278 push @parts,
279 $self->generate_part(
280 $c,
281 {
282 view => $part->{view},
283 template => $part->{template},
284 content_type => $part->{content_type},
285 charset => $part->{charset},
beda8c31 286 encoding => $part->{encoding},
287 }
ce1977b0 288 );
43090696 289 }
06afcdbc 290 }
ce1977b0 291
06afcdbc 292 # single part api
ce1977b0 293 elsif ( $c->stash->{$stash_key}->{template} ) {
69abdde2 294 my $part_args = { template => $c->stash->{$stash_key}->{template} };
295 if (my $ctype = $c->stash->{$stash_key}->{content_type}) {
296 $part_args->{content_type} = $ctype;
297 }
ce1977b0 298 push @parts,
69abdde2 299 $self->generate_part( $c, $part_args );
06afcdbc 300 }
ce1977b0 301
8b10ee55 302 delete $c->stash->{$stash_key}->{body};
303 $c->stash->{$stash_key}->{parts} ||= [];
ce1977b0 304 push @{ $c->stash->{$stash_key}->{parts} }, @parts;
1e331578 305
cce24d41 306 return $self->$orig($c);
ce1977b0 307
308};
529915ab 309
4a44bcd3 310=back
311
529915ab 312=head1 TODO
313
314=head2 ATTACHMENTS
315
316There needs to be a method to support attachments. What I am thinking is
317something along these lines:
25650747 318
529915ab 319 attachments => [
320 # Set the body to a file handle object, specify content_type and
321 # the file name. (name is what it is sent at, not the file)
322 { body => $fh, name => "foo.pdf", content_type => "application/pdf" },
323 # Or, specify a filename that is added, and hey, encoding!
324 { filename => "foo.gif", name => "foo.gif", content_type => "application/pdf", encoding => "quoted-printable" },
325 # Or, just a path to a file, and do some guesswork for the content type
326 "/path/to/somefile.pdf",
327 ]
328
329=head1 SEE ALSO
330
331=head2 L<Catalyst::View::Email> - Send plain boring emails with Catalyst
332
333=head2 L<Catalyst::Manual> - The Catalyst Manual
334
335=head2 L<Catalyst::Manual::Cookbook> - The Catalyst Cookbook
336
337=head1 AUTHORS
338
339J. Shirley <jshirley@gmail.com>
340
12c85b56 341Simon Elliott <cpan@browsing.co.uk>
342
4a44bcd3 343Alexander Hartmaier <abraxxa@cpan.org>
06afcdbc 344
529915ab 345=head1 LICENSE
346
347This library is free software, you can redistribute it and/or modify it under
348the same terms as Perl itself.
349
350=cut
351
3521;