Pod fix, adding parent to makefile
[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
ab4326b4 14our $VERSION = '0.11';
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',
6a68a57d 63 bcc => 'hidden@secret.com hidden2@foobar.com',
4a44bcd3 64 from => 'no-reply@foobar.com',
65 subject => 'I am a Catalyst generated email',
66 template => 'test.tt',
ab4326b4 67 content_type => 'multipart/alternative'
4a44bcd3 68 };
69
70 $c->forward( $c->view('Email::Template') );
71 }
529915ab 72
06afcdbc 73Alternatively if you want more control over your templates you can use the following idiom
74to override the defaults:
12c85b56 75
76 templates => [
06afcdbc 77 {
78 template => 'email/test.html.tt',
79 content_type => 'text/html',
ea115f9b 80 charset => 'utf-8',
06afcdbc 81 view => 'TT',
82 },
83 {
84 template => 'email/test.plain.mason',
85 content_type => 'text/plain',
ea115f9b 86 charset => 'utf-8',
06afcdbc 87 view => 'Mason',
88 }
12c85b56 89 ]
90
91
4a44bcd3 92=head1 HANDLING ERRORS
93
94See L<Catalyst::View::Email/HANDLING ERRORS>.
529915ab 95
96=cut
97
06afcdbc 98# here the defaults of Catalyst::View::Email are extended by the additional
99# ones Template.pm needs.
100
529915ab 101__PACKAGE__->config(
102 template_prefix => '',
103);
104
105
106# This view hitches into your default view and will call the render function
107# on the templates provided. This means that you have a layer of abstraction
108# and you aren't required to modify your templates based on your desired engine
109# (Template Toolkit or Mason, for example). As long as the view adequately
110# supports ->render, all things are good. Mason, and others, are not good.
111
112#
113# The path here is to check configuration for the template root, and then
114# proceed to call render on the subsequent templates and stuff each one
115# into an Email::MIME container. The mime-type will be stupidly guessed with
116# the subdir on the template.
117#
529915ab 118
06afcdbc 119# Set it up so if you have multiple parts, they're alternatives.
120# This is on the top-level message, not the individual parts.
121#multipart/alternative
529915ab 122
06afcdbc 123sub _validate_view {
124 my ($self, $view) = @_;
125
4a44bcd3 126 croak "C::V::Email::Template's configured view '$view' isn't an object!"
06afcdbc 127 unless (blessed($view));
128
4a44bcd3 129 croak "C::V::Email::Template's configured view '$view' isn't an Catalyst::View!"
06afcdbc 130 unless ($view->isa('Catalyst::View'));
131
4a44bcd3 132 croak "C::V::Email::Template's configured view '$view' doesn't have a render method!"
06afcdbc 133 unless ($view->can('render'));
134}
529915ab 135
4a44bcd3 136=head1 METHODS
137
138=over 4
11a0bf18 139
4a44bcd3 140=item generate_part
141
142Generates a MIME part to include in the email. Since the email is template based
11a0bf18 143every template piece is a separate part that is included in the email.
144
145=cut
146
43090696 147sub generate_part {
06afcdbc 148 my ($self, $c, $attrs) = @_;
d0e11256 149
06afcdbc 150 my $template_prefix = $self->{template_prefix};
151 my $default_view = $self->{default}->{view};
152 my $default_content_type = $self->{default}->{content_type};
ea115f9b 153 my $default_charset = $self->{default}->{charset};
154
ea115f9b 155 my $view;
156 # use the view specified for the email part
157 if (exists $attrs->{view} && defined $attrs->{view} && $attrs->{view} ne '') {
158 $view = $c->view($attrs->{view});
159 $c->log->debug("C::V::Email::Template uses specified view $view for rendering.") if $c->debug;
160 }
161 # if none specified use the configured default view
162 elsif ($default_view) {
163 $view = $c->view($default_view);
164 $c->log->debug("C::V::Email::Template uses default view $view for rendering.") if $c->debug;;
165 }
166 # else fallback to Catalysts default view
167 else {
168 $view = $c->view;
c649c40e 169 $c->log->debug("C::V::Email::Template uses Catalysts default view $view for rendering.") if $c->debug;;
ea115f9b 170 }
06afcdbc 171
06afcdbc 172 # validate the per template view
173 $self->_validate_view($view);
06afcdbc 174
175 # prefix with template_prefix if configured
176 my $template = $template_prefix ne '' ? join('/', $template_prefix, $attrs->{template}) : $attrs->{template};
ea115f9b 177
43090696 178 # setup the attributes (merge with defaults)
d0e11256 179 my $e_m_attrs = $self->setup_attributes($c, $attrs);
ea115f9b 180
06afcdbc 181 # render the email part
182 my $output = $view->render( $c, $template, {
ea115f9b 183 content_type => $e_m_attrs->{content_type},
184 stash_key => $self->{stash_key},
43090696 185 %{$c->stash},
06afcdbc 186 });
43090696 187
188 if ( ref $output ) {
189 croak $output->can('as_string') ? $output->as_string : $output;
529915ab 190 }
43090696 191
06afcdbc 192 return Email::MIME->create(
ea115f9b 193 attributes => $e_m_attrs,
43090696 194 body => $output,
06afcdbc 195 );
196}
529915ab 197
4a44bcd3 198=item process
11a0bf18 199
4a44bcd3 200The process method is called when the view is dispatched to. This creates the
11a0bf18 201multipart message and then sends the message contents off to
4a44bcd3 202L<Catalyst::View::Email> for processing, which in turn hands off to
203L<Email::Send>.
11a0bf18 204
205=cut
206
06afcdbc 207sub process {
e512f6ca 208 my ( $self, $c, @args ) = @_;
529915ab 209
06afcdbc 210 # don't validate template_prefix
8b10ee55 211
ea115f9b 212 # the default view is validated if used
12c85b56 213
06afcdbc 214 # the content type should be validated by Email::MIME::Creator
ea115f9b 215
216 my $stash_key = $self->{stash_key};
12c85b56 217
e512f6ca 218 # Go upstream if we don't have a template
219 $self->next::method($c, @args)
06afcdbc 220 unless $c->stash->{$stash_key}->{template}
221 or $c->stash->{$stash_key}->{templates};
222
223 # this array holds the Email::MIME objects
224 # in case of the simple api only one
225 my @parts = ();
12c85b56 226
06afcdbc 227 # now find out if the single or multipart api was used
228 # prefer the multipart one
229
230 # multipart api
231 if ($c->stash->{$stash_key}->{templates}
232 && ref $c->stash->{$stash_key}->{templates} eq 'ARRAY'
233 && ref $c->stash->{$stash_key}->{templates}[0] eq 'HASH') {
234 # loop through all parts of the mail
235 foreach my $part (@{$c->stash->{$stash_key}->{templates}}) {
43090696 236 push @parts, $self->generate_part($c, {
06afcdbc 237 view => $part->{view},
238 template => $part->{template},
239 content_type => $part->{content_type},
ea115f9b 240 charset => $part->{charset},
06afcdbc 241 });
43090696 242 }
06afcdbc 243 }
244 # single part api
245 elsif($c->stash->{$stash_key}->{template}) {
43090696 246 push @parts, $self->generate_part($c, {
06afcdbc 247 template => $c->stash->{$stash_key}->{template},
248 });
249 }
250
8b10ee55 251 delete $c->stash->{$stash_key}->{body};
252 $c->stash->{$stash_key}->{parts} ||= [];
253 push @{$c->stash->{$stash_key}->{parts}}, @parts;
529915ab 254
255 # Let C::V::Email do the actual sending. We just assemble the tasty bits.
256 return $self->next::method($c);
257}
258
4a44bcd3 259=back
260
529915ab 261=head1 TODO
262
263=head2 ATTACHMENTS
264
265There needs to be a method to support attachments. What I am thinking is
266something along these lines:
25650747 267
529915ab 268 attachments => [
269 # Set the body to a file handle object, specify content_type and
270 # the file name. (name is what it is sent at, not the file)
271 { body => $fh, name => "foo.pdf", content_type => "application/pdf" },
272 # Or, specify a filename that is added, and hey, encoding!
273 { filename => "foo.gif", name => "foo.gif", content_type => "application/pdf", encoding => "quoted-printable" },
274 # Or, just a path to a file, and do some guesswork for the content type
275 "/path/to/somefile.pdf",
276 ]
277
278=head1 SEE ALSO
279
280=head2 L<Catalyst::View::Email> - Send plain boring emails with Catalyst
281
282=head2 L<Catalyst::Manual> - The Catalyst Manual
283
284=head2 L<Catalyst::Manual::Cookbook> - The Catalyst Cookbook
285
286=head1 AUTHORS
287
288J. Shirley <jshirley@gmail.com>
289
12c85b56 290Simon Elliott <cpan@browsing.co.uk>
291
4a44bcd3 292Alexander Hartmaier <abraxxa@cpan.org>
06afcdbc 293
529915ab 294=head1 LICENSE
295
296This library is free software, you can redistribute it and/or modify it under
297the same terms as Perl itself.
298
299=cut
300
3011;