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