add support for differing views & content-type for each template
[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;
8
9use Email::MIME::Creator;
10
11use base qw|Catalyst::View::Email|;
12
25650747 13our $VERSION = '0.02';
529915ab 14
15=head1 NAME
16
17Catalyst::View::Email::Template - Send Templated Email from Catalyst
18
19=head1 SYNOPSIS
20
21Sends Templated mail, based upon your Default View. Will capture the output
22of the rendering path, slurps in based on mime-types and assembles a multi-part
23email and sends it out.
24
25=head2 CONFIGURATION
26
27 View::Email::Template:
28 # Set it up so if you have multiple parts, they're alternatives.
29 # This is on the top-level message, not the individual parts.
30 content_type: multipart/alternative
31 # Optional prefix to look somewhere under the existing configured
32 # template paths.
33 template_prefix: email
34 # Where to look in the stash for the email information
35 stash_key: email
36 # Setup how to send the email
37 sender:
38 method: SMTP
39 host: smtp.myhost.com
40 username: username
41 password: password
42
43=head1 SENDING EMAIL
44
45Sending email is just setting up your stash key, and forwarding to the view.
46
47 $c->stash->{email} = {
48 to => 'jshirley@gmail.com',
49 from => 'no-reply@foobar.com',
50 subject => 'I am a Catalyst generated email',
51 # Specify which templates to include
52 templates => [
53 qw{text_plain/test.tt},
54 qw{text_html/test.tt}
55 ]
56 };
57 $c->forward('View::Email::Template');
58
12c85b56 59Alternatively if you want more control over your templates you can use the following idiom :-
60
61 templates => [
62 { view => 'HTML',
63 template => 'email/test.html.tt',
64 content_type => 'text/html'
65 },
66 { view => 'Text',
67 template => 'email/test.plain.tt',
68 content_type => 'text/plain'
69 }
70
71 ]
72
73
529915ab 74If it fails $c->error will have the error message.
75
76=cut
77
78__PACKAGE__->config(
79 template_prefix => '',
80);
81
82
83# This view hitches into your default view and will call the render function
84# on the templates provided. This means that you have a layer of abstraction
85# and you aren't required to modify your templates based on your desired engine
86# (Template Toolkit or Mason, for example). As long as the view adequately
87# supports ->render, all things are good. Mason, and others, are not good.
88
89#
90# The path here is to check configuration for the template root, and then
91# proceed to call render on the subsequent templates and stuff each one
92# into an Email::MIME container. The mime-type will be stupidly guessed with
93# the subdir on the template.
94#
95# TODO: Make this unretarded.
96#
97sub process {
98 my ( $self, $c ) = @_;
99
100 my $stash_key = $self->config->{stash_key} || 'email';
101
102 croak "No template specified for rendering"
103 unless $c->stash->{$stash_key}->{template} or
104 $c->stash->{$stash_key}->{templates};
529915ab 105 # Where to look
106 my $template_prefix = $self->config->{template_prefix};
107 my @templates = ();
12c85b56 108
109 if ( $c->stash->{$stash_key}->{templates} && !ref $c->stash->{$stash_key}->{templates}[0]) {
529915ab 110 push @templates, map {
111 join('/', $template_prefix, $_);
112 } @{$c->stash->{$stash_key}->{templates}};
113
12c85b56 114 } elsif($c->stash->{$stash_key}->{template}) {
529915ab 115 push @templates, join('/', $template_prefix,
116 $c->stash->{$stash_key}->{template});
117 }
118
119 my $default_view = $c->view( $self->config->{default_view} );
120
121 unless ( $default_view->can('render') ) {
122 croak "Email::Template's configured view does not have a render method!";
123 }
124
125 #$c->log->_dump($default_view->config);
126
127 my @parts = ();
128 foreach my $template ( @templates ) {
129 $template =~ s#^/+##; # Make sure that we don't have an absolute path.
130 # This seems really stupid to me... argh. will give me nightmares!
131 my $template_path = $template;
132 $template_path =~ s#^$template_prefix/##;
133 my ( $content_type, $extra ) = split('/', $template_path);
134 if ( $extra ) {
135 $content_type ||= 'text/plain';
136 $content_type =~ s#_#/#;
137 } else {
138 $content_type = 'text/plain';
139 }
140 my $output = $default_view->render( $c, $template,
81e9d470 141 { content_type => $content_type, %{$c->stash} });
529915ab 142 # Got a ref, not a scalar. An error!
143 if ( ref $output ) {
144 croak $output->can("as_string") ? $output->as_string : $output;
145 }
146 push @parts, Email::MIME->create(
147 attributes => {
148 content_type => $content_type
149 },
150 body => $output
151 );
152 }
12c85b56 153
154 #add user parts :-
155 if ( $c->stash->{$stash_key}->{'templates'} && ref $c->stash->{$stash_key}->{templates}[0] ) {
156 foreach my $part (@{$c->stash->{$stash_key}->{'templates'}}) {
157 my $view = $c->view($part->{'view'} || $self->config->{default_view});
158
159 my $content_type = $part->{'content_type'} || 'text/plain';
160 unless ( $view->can('render') ) {
161 croak "Part does not have valid render view";
162 }
163
164 my $output = $view->render( $c, $part->{'template'}, {
165 'content_type' => $content_type,
166 %{$c->stash} });
167
168 if ( ref $output ) {
169 croak $output->can("as_string") ? $output->as_string : $output;
170 }
171
172 push @parts, Email::MIME->create(
173 attributes => {
174 content_type => $content_type
175 },
176 body => $output
177 );
178 }
179 }
180
529915ab 181 delete $c->stash->{email}->{body};
182 $c->stash->{email}->{parts} ||= [];
183 push @{$c->stash->{email}->{parts}}, @parts;
184
185 # Let C::V::Email do the actual sending. We just assemble the tasty bits.
186 return $self->next::method($c);
187}
188
189=head1 TODO
190
191=head2 ATTACHMENTS
192
193There needs to be a method to support attachments. What I am thinking is
194something along these lines:
25650747 195
529915ab 196 attachments => [
197 # Set the body to a file handle object, specify content_type and
198 # the file name. (name is what it is sent at, not the file)
199 { body => $fh, name => "foo.pdf", content_type => "application/pdf" },
200 # Or, specify a filename that is added, and hey, encoding!
201 { filename => "foo.gif", name => "foo.gif", content_type => "application/pdf", encoding => "quoted-printable" },
202 # Or, just a path to a file, and do some guesswork for the content type
203 "/path/to/somefile.pdf",
204 ]
205
206=head1 SEE ALSO
207
208=head2 L<Catalyst::View::Email> - Send plain boring emails with Catalyst
209
210=head2 L<Catalyst::Manual> - The Catalyst Manual
211
212=head2 L<Catalyst::Manual::Cookbook> - The Catalyst Cookbook
213
214=head1 AUTHORS
215
216J. Shirley <jshirley@gmail.com>
217
12c85b56 218Simon Elliott <cpan@browsing.co.uk>
219
529915ab 220=head1 LICENSE
221
222This library is free software, you can redistribute it and/or modify it under
223the same terms as Perl itself.
224
225=cut
226
2271;
228