File Coverage

blib/lib/CAM/EmailTemplate.pm
Criterion Covered Total %
statement 12 69 17.3
branch 0 28 0.0
condition 0 3 0.0
subroutine 4 8 50.0
pod 3 3 100.0
total 19 111 17.1


line stmt bran cond sub pod time code
1             package CAM::EmailTemplate;
2              
3             =head1 NAME
4              
5             CAM::EmailTemplate - Template-based email message sender
6              
7             =head1 LICENSE
8              
9             Copyright 2005 Clotho Advanced Media, Inc.,
10              
11             This library is free software; you can redistribute it and/or modify it
12             under the same terms as Perl itself.
13              
14             =head1 SEE ALSO
15              
16             There are many, many other templating and emailing modules on CPAN.
17             Unless you have a specific reason for using this one, you may have
18             better searching for a different one.
19              
20             This module is a bit clumsy in the way it sends email (relying on
21             Sendmail), and doesn't thoroughly ensure that the outgoing emails are
22             valid, but it is very handy in its integration with a templating
23             engine.
24              
25             =head1 SYNOPSIS
26              
27             use CAM::EmailTemplate;
28            
29             my $template = new CAM::EmailTemplate($filename);
30             $template->setParams(recipient => 'user@foo.com',
31             bar => 'baz', kelp => 'green');
32             if ($template->send()) {
33             print 'Sent.';
34             } else {
35             print 'Doh! ' . $template->{sendError};
36             }
37              
38             =head1 DESCRIPTION
39              
40             CAM::EmailTemplate extends CAM::Template for sending template-based
41             email messages. The mechanism for sending is 'sendmail -i -t' so this
42             module requires that the computer is a Unixish machine set up for
43             sending. Many simple but handy sanity tests are performed by the
44             send() function.
45              
46             The template itself must contain all of the requisite mail header
47             info, including 'To:' and 'From:' lines. Read the EXAMPLES section
48             below to see demos of what this looks like.
49              
50             =cut
51              
52             require 5.005_62;
53 1     1   23373 use strict;
  1         3  
  1         43  
54 1     1   6 use warnings;
  1         2  
  1         27  
55 1     1   6 use Carp;
  1         1  
  1         81  
56 1     1   888 use CAM::Template;
  1         3288  
  1         711  
57              
58             our @ISA = qw(CAM::Template);
59             our $VERSION = '0.92';
60              
61             # Package globals
62              
63             my @global_possible_paths = (
64             "/usr/bin/sendmail",
65             "/usr/lib/sendmail",
66             "/usr/ucblib/sendmail",
67             );
68             my $global_sendmail_path = ""; # cache the path when we find it
69              
70              
71             =head1 INSTANCE METHODS
72              
73             =over 4
74              
75             =cut
76              
77             =item setEnvelopSender ADDRESS
78              
79             Changed the sender as reported by sendmail to the remote host. Note
80             that this may be visible to the end recipient.
81              
82             =cut
83              
84             sub setEnvelopSender
85             {
86 0     0 1   my $self = shift;
87 0           my $sender = shift;
88              
89 0           $self->{envelopSender} = $sender;
90             }
91              
92             =item send
93              
94             Fill the template and send it out. If there is an error (badly
95             formatted message, sendmail error, etc), this function returns undef.
96             In this case, an explanatory string for the error can be obtained from
97             the $template->{sendError} property.
98              
99             =cut
100              
101             sub send
102             {
103 0     0 1   my $self = shift;
104              
105 0           $self->{sendError} = undef;
106              
107 0           my $content = $self->toString();
108 0 0         if (!$content)
109             {
110 0           $self->{sendError} = "Did not find the template.";
111 0           return undef;
112             }
113              
114 0 0         if ($content !~ /\n$/s)
115             {
116 0           &carp("Appending a newline to the end of the email message");
117 0           $content .= "\n";
118             }
119              
120 0 0         if ($content !~ /^(.*\n)\n/s)
121             {
122 0           $self->{sendError} = "Did not find the end of the email header.";
123 0           return undef;
124             }
125              
126 0           my $header = $1;
127 0           foreach my $fieldname ("To:", "From:")
128             {
129 0 0         if ($header !~ /^$fieldname\s+(\S+.*?)$/m)
130             {
131 0           $self->{sendError} = "There is no '$fieldname' field in the email header.";
132 0           return undef;
133             }
134 0           my @addrs = split /,/, $1;
135 0           foreach my $addr (@addrs) {
136 0 0 0       if ($addr !~ /^\s*[^@]+@[^@]+\s*$/ &&
137             $addr !~ /^\s*[^,<@]*<[^@]+@[^@]+>\s*/)
138             {
139 0           $self->{sendError} = "Invalid email address in '$addr' in the $fieldname header field.";
140 0           return undef;
141             }
142             }
143             }
144 0 0         if ($header !~ /^Subject: /m)
145             {
146 0           $self->{sendError} = "There is no 'Subject:' field in the email header.";
147 0           return undef;
148             }
149            
150             # Do the actual delivery now
151 0           my ($success, $error) = $self->deliver($content);
152 0 0         if ($success)
153             {
154 0           return $self;
155             }
156             else
157             {
158 0           $self->{sendError} = $error;
159 0           return undef;
160             }
161             }
162              
163             =item deliver MSG
164              
165             Delivers the message. This function assumes that the message is
166             properly formatted.
167              
168             This function should ONLY be called from with the send() method. It
169             is provided here so that it can be overridden by subclasses.
170              
171             It should return an array of two values: either (true, undef) or
172             (false, errormessage) indicating success or failure.
173              
174             This particular implementation relies on the existance of a sendmail
175             binary on the host machine.
176              
177             =cut
178              
179             sub deliver
180             {
181 0     0 1   my $self = shift;
182 0           my $content = shift;
183              
184 0           my $error = undef;
185 0           my $sendmail = $self->_getSendmailPath();
186 0 0         if (!$sendmail)
187             {
188 0           $error = "Could not find the mail agent program.";
189             }
190             else
191             {
192 0           local $ENV{PATH} = "";
193 0           local *MAIL;
194 0           my $cmd = "$sendmail -i -t";
195 0 0         if ($self->{envelopeSender})
196             {
197 0           $cmd .= " -f".$self->{envelopeSender};
198             }
199 0 0         if (!open (MAIL, "| $cmd"))
200             {
201 0           $error = "Failed to contact the mail agent";
202             }
203             else
204             {
205 0           print MAIL $content;
206            
207 0 0         if (!close(MAIL))
208             {
209 0           $error = "The mail agent did not complete the message delivery";
210             }
211             }
212             }
213 0 0         return $error ? (undef, $error) : ($self, undef);
214             }
215              
216             ## Internal function
217             # find the sendmail executable
218             sub _getSendmailPath
219             {
220 0     0     my $self = shift;
221              
222 0 0         if (!$global_sendmail_path)
223             {
224 0           foreach my $try (@global_possible_paths) {
225 0 0         if (-x $try)
226             {
227 0           $global_sendmail_path = $try;
228 0           last;
229             }
230             }
231              
232             }
233 0           return $global_sendmail_path;
234             }
235              
236             1;
237             __END__