summaryrefslogtreecommitdiffstats
path: root/Bugzilla/Mailer.pm
diff options
context:
space:
mode:
authormkanat%bugzilla.org <>2006-11-03 08:31:59 +0100
committermkanat%bugzilla.org <>2006-11-03 08:31:59 +0100
commit394a014b635238518511e1c86ecdbdbe70593c5c (patch)
treec57be0489271f2a84bcf3eabfbc26bdaae32e8c9 /Bugzilla/Mailer.pm
parentc387f4db6121b465c4d10035d8082eee3c016ef0 (diff)
downloadbugzilla-394a014b635238518511e1c86ecdbdbe70593c5c.tar.gz
bugzilla-394a014b635238518511e1c86ecdbdbe70593c5c.tar.xz
Bug 353711: Move to Email:: modules for email sending
Patch By Max Kanat-Alexander <mkanat@bugzilla.org> r=glob, a=myk
Diffstat (limited to 'Bugzilla/Mailer.pm')
-rw-r--r--Bugzilla/Mailer.pm206
1 files changed, 51 insertions, 155 deletions
diff --git a/Bugzilla/Mailer.pm b/Bugzilla/Mailer.pm
index 2105d38ae..633964b33 100644
--- a/Bugzilla/Mailer.pm
+++ b/Bugzilla/Mailer.pm
@@ -28,6 +28,7 @@
# Gervase Markham <gerv@gerv.net>
# Byron Jones <bugzilla@glob.com.au>
# Frédéric Buclin <LpSolit@gmail.com>
+# Max Kanat-Alexander <mkanat@bugzilla.org>
package Bugzilla::Mailer;
@@ -37,181 +38,76 @@ use base qw(Exporter);
@Bugzilla::Mailer::EXPORT = qw(MessageToMTA);
use Bugzilla::Constants;
+use Bugzilla::Error;
use Bugzilla::Util;
-use Mail::Header;
-use Mail::Mailer;
-use Mail::Address;
-use MIME::Parser;
-use MIME::QuotedPrint;
-use MIME::Base64;
-
+use Encode qw(encode);
+use Email::MIME;
+# Loading this gives us encoding_set.
+use Email::MIME::Modifier;
+use Email::Send;
sub MessageToMTA {
my ($msg) = (@_);
- my $params = Bugzilla->params;
- return if ($params->{'mail_delivery_method'} eq "none");
-
- my ($header, $body) = $msg =~ /(.*?\n)\n(.*)/s ? ($1, $2) : ('', $msg);
- my $headers;
+ my $method = Bugzilla->params->{'mail_delivery_method'};
+ return if $method eq 'None';
- if ($params->{'utf8'}
- and (!is_7bit_clean($header) or !is_7bit_clean($body)))
- {
- ($headers, $body) = encode_message($msg);
- } else {
- my @header_lines = split(/\n/, $header);
- $headers = new Mail::Header \@header_lines, Modify => 0;
+ my $email = ref($msg) ? $msg : Email::MIME->new($msg);
+ foreach my $part ($email->parts) {
+ $part->charset_set('UTF-8') if Bugzilla->params->{'utf8'};
+ $part->encoding_set('quoted-printable') if !is_7bit_clean($part->body);
}
- # Use trim to remove any whitespace (incl. newlines)
- my $from = trim($headers->get('from'));
-
- if ($params->{"mail_delivery_method"} eq "sendmail" && $^O =~ /MSWin32/i) {
- my $cmd = '|' . SENDMAIL_EXE . ' -t -i';
- if ($from) {
- # We're on Windows, thus no danger of command injection
- # via $from. In other words, it is safe to embed $from.
- $cmd .= qq# -f"$from"#;
+ # Encode the headers correctly in quoted-printable
+ foreach my $header qw(From To Cc Reply-To Sender Errors-To Subject) {
+ if (my $value = $email->header($header)) {
+ my $encoded = encode('MIME-Q', $value);
+ $email->header_set($header, $encoded);
}
- open(SENDMAIL, $cmd) ||
- die "Failed to execute " . SENDMAIL_EXE . ": $!\n";
- print SENDMAIL $headers->as_string;
- print SENDMAIL "\n";
- print SENDMAIL $body;
- close SENDMAIL;
- return;
}
- my @args;
- if ($params->{"mail_delivery_method"} eq "sendmail") {
- push @args, "-i";
- if ($from) {
- push(@args, "-f$from");
- }
- }
- if ($params->{"mail_delivery_method"} eq "sendmail"
- && !$params->{"sendmailnow"})
- {
- push @args, "-ODeliveryMode=deferred";
- }
- if ($params->{"mail_delivery_method"} eq "smtp") {
- push @args, Server => $params->{"smtpserver"};
- if ($from) {
- $ENV{'MAILADDRESS'} = $from;
+ my $from = $email->header('From');
+
+ my ($hostname, @args);
+ if ($method eq "Sendmail") {
+ if (ON_WINDOWS) {
+ $Email::Send::Sendmail::SENDMAIL = SENDMAIL_EXE;
}
+ push @args, "-i";
+ push(@args, "-f$from") if $from;
+ push(@args, "-ODeliveryMode=deferred")
+ if !Bugzilla->params->{"sendmailnow"};
}
- my $mailer = new Mail::Mailer($params->{"mail_delivery_method"}, @args);
- if ($params->{"mail_delivery_method"} eq "testfile") {
- $Mail::Mailer::testfile::config{outfile} =
- bz_locations()->{'datadir'} . '/mailer.testfile';
- }
-
- $mailer->open($headers->header_hashref);
- print $mailer $body;
- $mailer->close;
-}
-
-sub encode_message {
- my ($msg) = @_;
-
- my $parser = MIME::Parser->new;
- $parser->output_to_core(1);
- $parser->tmp_to_core(1);
- my $entity = $parser->parse_data($msg);
- $entity = encode_message_entity($entity);
-
- my @header_lines = split(/\n/, $entity->header_as_string);
- my $head = new Mail::Header \@header_lines, Modify => 0;
-
- my $body = $entity->body_as_string;
-
- return ($head, $body);
-}
-
-sub encode_message_entity {
- my ($entity) = @_;
-
- my $head = $entity->head;
-
- # encode the subject
-
- my $subject = $head->get('subject');
- if (defined $subject && !is_7bit_clean($subject)) {
- $subject =~ s/[\r\n]+$//;
- $head->replace('subject', encode_qp_words($subject));
+ else {
+ # Sendmail will automatically append our hostname to the From
+ # address, but other mailers won't.
+ my $urlbase = Bugzilla->params->{'urlbase'};
+ $urlbase =~ m|//([^/]+)/?|;
+ $hostname = $1;
+ $from .= "\@$hostname" if $from !~ /@/;
+ $email->header_set('From', $from);
}
- # encode addresses
-
- foreach my $field (qw(from to cc reply-to sender errors-to)) {
- my $high = $head->count($field) - 1;
- foreach my $index (0..$high) {
- my $value = $head->get($field, $index);
- my @addresses;
- my $changed = 0;
- foreach my $addr (Mail::Address->parse($value)) {
- my $phrase = $addr->phrase;
- if (is_7bit_clean($phrase)) {
- push @addresses, $addr->format;
- } else {
- push @addresses, encode_qp_phrase($phrase) .
- ' <' . $addr->address . '>';
- $changed = 1;
- }
- }
- $changed && $head->replace($field, join(', ', @addresses), $index);
- }
+ if ($method eq "SMTP") {
+ push @args, Host => Bugzilla->params->{"smtpserver"},
+ Hello => $hostname;
}
- # process the body
-
- if (scalar($entity->parts)) {
- my $newparts = [];
- foreach my $part ($entity->parts) {
- my $newpart = encode_message_entity($part);
- push @$newparts, $newpart;
- }
- $entity->parts($newparts);
+ if ($method eq "Test") {
+ my $filename = bz_locations()->{'datadir'} . '/mailer.testfile';
+ open TESTFILE, '>>', $filename;
+ print TESTFILE "\n\n---\n\n" . $email->as_string;
+ close TESTFILE;
}
else {
- # Extract the body from the entity, for examination
- # At this point, we can rely on MIME::Tools to do our encoding for us!
- my $bodyhandle = $entity->bodyhandle;
- my $body = $bodyhandle->as_string;
- if (!is_7bit_clean($body)) {
- # count number of 7-bit chars, and use quoted-printable if more
- # than half the message is 7-bit clean
- my $count = ($body =~ tr/\x20-\x7E\x0A\x0D//);
- if ($count > length($body) / 2) {
- $head->mime_attr('Content-Transfer-Encoding' => 'quoted-printable');
- } else {
- $head->mime_attr('Content-Transfer-Encoding' => 'base64');
- }
- }
-
- # Set the content/type and charset of the part, if not set
- $head->mime_attr('Content-Type' => 'text/plain')
- unless defined $head->mime_attr('content-type');
- $head->mime_attr('Content-Type.charset' => 'UTF-8');
- }
-
- $head->mime_attr('MIME-Version' => '1.0');
- $head->fold(75);
- return $entity;
-}
-
-sub encode_qp_words {
- my ($line) = (@_);
- my @encoded;
- foreach my $word (split / /, $line) {
- if (!is_7bit_clean($word)) {
- push @encoded, '=?UTF-8?Q?_' . encode_qp($word, '') . '?=';
- } else {
- push @encoded, $word;
- }
+ # This is useful for both Sendmail and Qmail, so we put it out here.
+ local $ENV{PATH} = SENDMAIL_PATH;
+ my $mailer = Email::Send->new({ mailer => $method,
+ mailer_args => \@args });
+ my $retval = $mailer->send($email);
+ ThrowCodeError('mail_send_error', { msg => $retval, mail => $email })
+ if !$retval;
}
- return join(' ', @encoded);
}
1;