root/branches/release-33/lib/MT/Mail.pm @ 1680

Revision 1680, 7.6 kB (checked in by bchoate, 20 months ago)

Preserve id parameter to Mail send method across multiple calls. BugId:68724

  • Property svn:keywords set to Author Date Id Revision
Line 
1# Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd.
2# This program is distributed under the terms of the
3# GNU General Public License, version 2.
4#
5# $Id$
6
7package MT::Mail;
8
9use strict;
10
11use MT;
12use base qw( MT::ErrorHandler );
13use MT::I18N qw(encode_text);
14
15sub send {
16    my $class = shift;
17    my($hdrs_arg, $body) = @_;
18
19    local $hdrs_arg->{id} = $hdrs_arg->{id};
20    my $id = delete $hdrs_arg->{id};
21
22    my %hdrs = map { $_ => $hdrs_arg->{$_} } keys %$hdrs_arg;
23    foreach my $h (keys %hdrs) {
24        if (ref($hdrs{$h}) eq 'ARRAY') {
25            map { y/\n\r/  / } @{$hdrs{$h}};
26        } else {
27            $hdrs{$h} =~ y/\n\r/  / unless (ref($hdrs{$h}));
28        }
29    }
30   
31    my $mgr = MT->config;
32    my $xfer = $mgr->MailTransfer;
33
34    my $enc = $mgr->PublishCharset;
35    my $mail_enc = uc ($mgr->MailEncoding || $enc);
36
37
38    $body = encode_text($body, $enc, lc $mail_enc);
39
40    eval "require MIME::EncWords;";
41    unless ($@) {
42        foreach my $header (keys %hdrs) {
43            my $val = $hdrs{$header};
44
45            if (ref $val eq 'ARRAY') {
46                foreach (@$val) {
47                    if ((lc($mail_enc) ne 'iso-8859-1') || (m/[^[:print:]]/)) {
48                        if ($header =~ m/^(From|To|Reply|B?cc)/i) {
49                            if (m/^(.+?)\s*(<[^@>]+@[^>]+>)\s*$/) {
50                                $_ = MIME::EncWords::encode_mimeword(
51                                    encode_text($1, $enc, lc $mail_enc), 'b', lc $mail_enc) . ' ' . $2;
52                            }
53                        } elsif ($header !~ m/^(Content-Type|Content-Transfer-Encoding|MIME-Version)/i) {
54                            $_ = MIME::EncWords::encode_mimeword(
55                                    encode_text($_, $enc, lc $mail_enc), 'b', lc $mail_enc);
56                        }
57                    }
58                }
59            } else {
60                if ((lc($mail_enc) ne 'iso-8859-1') || ($val =~ /[^[:print:]]/)) {
61                    if ($header =~ m/^(From|To|Reply|B?cc)/i) {
62                        if ($val =~ m/^(.+?)\s*(<[^@>]+@[^>]+>)\s*$/) {
63                            $hdrs{$header} = MIME::EncWords::encode_mimeword(
64                                    encode_text($1, $enc, lc $mail_enc), 'b', lc $mail_enc) . ' ' . $2;
65                        }
66                    } elsif ($header !~ m/^(Content-Type|Content-Transfer-Encoding|MIME-Version)/i) {
67                        $hdrs{$header} = MIME::EncWords::encode_mimeword(
68                            encode_text($val, $enc, lc $mail_enc), 'b', lc $mail_enc);
69                    }
70                }
71            }
72        }
73    } else {
74        $hdrs{Subject} = encode_text($hdrs{Subject}, $enc, lc $mail_enc);
75        $hdrs{From} = encode_text($hdrs{From}, $enc, lc $mail_enc);
76    }
77    $hdrs{'Content-Type'} ||= qq(text/plain; charset=") . lc $mail_enc . q(");
78    $hdrs{'Content-Transfer-Encoding'} = ((lc $mail_enc) !~ m/utf-?8/) ? '7bit' : '8bit';
79    $hdrs{'MIME-Version'} ||= "1.0";
80
81    return 1 unless
82        MT->run_callbacks('mail_filter', args => $hdrs_arg, headers => \%hdrs,
83            body => \$body, transfer => \$xfer, ( $id ? ( id => $id ) : () ) );
84
85    if ($xfer eq 'sendmail') {
86        return $class->_send_mt_sendmail(\%hdrs, $body, $mgr);
87    } elsif ($xfer eq 'smtp') {
88        return $class->_send_mt_smtp(\%hdrs, $body, $mgr);
89    } elsif ($xfer eq 'debug') {
90        return $class->_send_mt_debug(\%hdrs, $body, $mgr);
91    } else {
92        return $class->error(MT->translate(
93            "Unknown MailTransfer method '[_1]'", $xfer ));
94    }
95}
96
97use MT::Util qw(is_valid_email);
98
99sub _send_mt_debug {
100    my $class = shift;
101    my($hdrs, $body, $mgr) = @_;
102    $hdrs->{To} = $mgr->DebugEmailAddress
103        if (is_valid_email($mgr->DebugEmailAddress||''));
104    for my $key (keys %$hdrs) {
105        my @arr = ref($hdrs->{$key}) eq 'ARRAY' ?
106            @{ $hdrs->{$key} } : ($hdrs->{$key});
107        print STDERR map "$key: $_\n", @arr;
108    }
109    print STDERR "\n";
110    print STDERR $body;
111    1;
112}
113
114sub _send_mt_smtp {
115    my $class = shift;
116    my($hdrs, $body, $mgr) = @_;
117    eval { require Mail::Sendmail; };
118    return $class->error(MT->translate(
119        "Sending mail via SMTP requires that your server " .
120        "have Mail::Sendmail installed: [_1]", $@ )) if $@;
121    my %hdrs = %$hdrs;
122    $hdrs{Message} = $body;
123    $hdrs{Smtp} = $mgr->SMTPServer;
124    for my $h (qw( Cc Bcc )) {
125        if ($hdrs{$h}) {
126            $hdrs{$h} = join ', ', @{ $hdrs{$h} };
127        }
128    }
129    my $ret = Mail::Sendmail::sendmail(%hdrs);
130    $ret or return $class->error(MT->translate(
131        "Error sending mail: [_1]", $Mail::Sendmail::error ));
132    1;
133}
134
135my @Sendmail = qw( /usr/lib/sendmail /usr/sbin/sendmail /usr/ucblib/sendmail );
136sub _send_mt_sendmail {
137    my $class = shift;
138    my($hdrs, $body, $mgr) = @_;
139    $hdrs->{To} = $mgr->DebugEmailAddress
140        if (is_valid_email($mgr->DebugEmailAddress||''));
141    my $sm_loc;
142    for my $loc ($mgr->SendMailPath, @Sendmail) {
143        next unless $loc;
144        $sm_loc = $loc, last if -x $loc && !-d $loc;
145    }
146    return $class->error(MT->translate(
147        "You do not have a valid path to sendmail on your machine. " .
148        "Perhaps you should try using SMTP?" ))
149        unless $sm_loc;
150    local $SIG{PIPE} = { };
151    my $pid = open MAIL, '|-';
152    local $SIG{ALRM} = sub { CORE::exit() };
153    return unless defined $pid;
154    if (!$pid) {
155        exec $sm_loc, "-oi", "-t" or
156            return $class->error(MT->translate(
157                "Exec of sendmail failed: [_1]", "$!" ));
158    }
159    for my $key (keys %$hdrs) {
160        my @arr = ref($hdrs->{$key}) eq 'ARRAY' ?
161            @{ $hdrs->{$key} } : ($hdrs->{$key});
162        print MAIL map "$key: $_\n", @arr;
163    }
164    print MAIL "\n";
165    print MAIL $body;
166    close MAIL;
167    1;
168}
169
1701;
171__END__
172
173=head1 NAME
174
175MT::Mail - Movable Type mail sender
176
177=head1 SYNOPSIS
178
179    use MT::Mail;
180    my %head = ( To => 'foo@bar.com', Subject => 'My Subject' );
181    my $body = 'This is the body of the message.';
182    MT::Mail->send(\%head, $body)
183        or die MT::Mail->errstr;
184
185=head1 DESCRIPTION
186
187I<MT::Mail> is the Movable Type mail-sending interface. It can send mail
188through I<sendmail> (in several different default locations), through SMTP,
189or through a debugging interface that writes data to STDERR. You can set the
190method of sending mail through the F<mt.cfg> file by changing the value for
191the I<MailTransfer> setting to one of the following values: C<sendmail>,
192C<smtp>, or C<debug>.
193
194If you are using C<sendmail>, I<MT::Mail::send> looks for your I<sendmail>
195program in any of the following locations: F</usr/lib/sendmail>,
196F</usr/sbin/sendmail>, and F</usr/ucblib/sendmail>. If your I<sendmail> is at
197a different location, you can set it using the I<SendMailPath> directive.
198
199If you are using C<smtp>, I<MT::Mail::send> will by default use C<localhost>
200as the SMTP server. You can change this by setting the I<SMTPServer>
201directive.
202
203=head1 USAGE
204
205=head2 MT::Mail->send(\%headers, $body)
206
207Sends a mail message with the headers I<\%headers> and the message body
208I<$body>.
209
210The keys and values in I<\%headers> are passed directly in to the mail
211program or server, so you can use any valid mail header names as keys. If
212you need to supply a list of header values, specify the hash value as a
213reference to a list of the header values. For example:
214
215    %headers = ( Bcc => [ 'foo@bar.com', 'baz@quux.com' ] );
216
217If you wish the lines in I<$body> to be wrapped, you should do this yourself;
218it will not be done by I<send>.
219
220On success, I<send> returns true; on failure, it returns C<undef>, and the
221error message is in C<MT::Mail-E<gt>errstr>.
222
223=head1 AUTHOR & COPYRIGHT
224
225Please see the I<MT> manpage for author, copyright, and license information.
226
227=cut
Note: See TracBrowser for help on using the browser.