mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-02 07:05:24 +00:00
Bug 353711: Move to Email:: modules for email sending
Patch By Max Kanat-Alexander <mkanat@bugzilla.org> r=glob, a=myk
This commit is contained in:
parent
089c4941f6
commit
b8528fccb9
@ -81,6 +81,9 @@ sub init_page {
|
||||
|
||||
# Some environment variables are not taint safe
|
||||
delete @::ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
|
||||
# Some modules throw undefined errors (notably File::Spec::Win32) if
|
||||
# PATH is undefined.
|
||||
$ENV{'PATH'} = '';
|
||||
|
||||
# If Bugzilla is shut down, do not allow anything to run, just display a
|
||||
# message to the user about the downtime and log out. Scripts listed in
|
||||
|
@ -171,6 +171,19 @@ sub update_params {
|
||||
delete $param->{'enablequips'};
|
||||
}
|
||||
|
||||
# Old mail_delivery_method choices contained no uppercase characters
|
||||
if (exists $param->{'mail_delivery_method'}
|
||||
&& $param->{'mail_delivery_method'} !~ /[A-Z]/) {
|
||||
my $method = $param->{'mail_delivery_method'};
|
||||
my %translation = (
|
||||
'sendmail' => 'Sendmail',
|
||||
'smtp' => 'SMTP',
|
||||
'qmail' => 'Qmail',
|
||||
'testfile' => 'Test',
|
||||
'none' => 'None');
|
||||
$param->{'mail_delivery_method'} = $translation{$method};
|
||||
}
|
||||
|
||||
# --- DEFAULTS FOR NEW PARAMS ---
|
||||
|
||||
_load_params unless %params;
|
||||
@ -216,7 +229,7 @@ sub update_params {
|
||||
}
|
||||
|
||||
if (ON_WINDOWS && !-e SENDMAIL_EXE
|
||||
&& $param->{'mail_delivery_method'} eq 'sendmail')
|
||||
&& $param->{'mail_delivery_method'} eq 'Sendmail')
|
||||
{
|
||||
my $smtp = $answer->{'SMTP_SERVER'};
|
||||
if (!$smtp) {
|
||||
@ -233,7 +246,7 @@ sub update_params {
|
||||
}
|
||||
}
|
||||
|
||||
$param->{'mail_delivery_method'} = 'smtp';
|
||||
$param->{'mail_delivery_method'} = 'SMTP';
|
||||
}
|
||||
|
||||
write_params($param);
|
||||
|
@ -34,6 +34,7 @@ package Bugzilla::Config::MTA;
|
||||
use strict;
|
||||
|
||||
use Bugzilla::Config::Common;
|
||||
use Email::Send;
|
||||
|
||||
$Bugzilla::Config::MTA::sortkey = "10";
|
||||
|
||||
@ -43,10 +44,8 @@ sub get_param_list {
|
||||
{
|
||||
name => 'mail_delivery_method',
|
||||
type => 's',
|
||||
choices => $^O =~ /MSWin32/i
|
||||
? ['smtp', 'testfile', 'sendmail', 'none']
|
||||
: ['sendmail', 'smtp', 'qmail', 'testfile', 'none'],
|
||||
default => 'sendmail',
|
||||
choices => [Email::Send->new()->all_mailers(), 'None'],
|
||||
default => 'Sendmail',
|
||||
checker => \&check_mail_delivery_method
|
||||
},
|
||||
|
||||
|
@ -103,6 +103,7 @@ use File::Basename;
|
||||
ADMIN_GROUP_NAME
|
||||
|
||||
SENDMAIL_EXE
|
||||
SENDMAIL_PATH
|
||||
|
||||
FIELD_TYPE_UNKNOWN
|
||||
FIELD_TYPE_FREETEXT
|
||||
@ -290,6 +291,8 @@ use constant ADMIN_GROUP_NAME => 'admin';
|
||||
|
||||
# Path to sendmail.exe (Windows only)
|
||||
use constant SENDMAIL_EXE => '/usr/lib/sendmail.exe';
|
||||
# Paths to search for the sendmail binary (non-Windows)
|
||||
use constant SENDMAIL_PATH => '/usr/lib:/usr/sbin:/usr/ucblib';
|
||||
|
||||
# Field types. Match values in fielddefs.type column. These are purposely
|
||||
# not named after database column types, since Bugzilla fields comprise not
|
||||
|
@ -78,11 +78,6 @@ sub REQUIRED_MODULES {
|
||||
module => 'Template',
|
||||
version => '2.12'
|
||||
},
|
||||
{
|
||||
package => 'MailTools',
|
||||
module => 'Mail::Mailer',
|
||||
version => '1.67'
|
||||
},
|
||||
{
|
||||
package => 'MIME-Base64',
|
||||
module => 'MIME::Base64',
|
||||
@ -94,6 +89,17 @@ sub REQUIRED_MODULES {
|
||||
module => ON_WINDOWS ? 'MIME::Tools' : 'MIME::Parser',
|
||||
version => '5.406'
|
||||
},
|
||||
{
|
||||
package => 'Email-Send',
|
||||
module => 'Email::Send',
|
||||
version => ON_WINDOWS ? '2.16' : '2.00'
|
||||
},
|
||||
{
|
||||
# This will pull in Email::MIME for us, also.
|
||||
package => 'Email-MIME-Modifier',
|
||||
module => 'Email::MIME::Modifier',
|
||||
version => 0
|
||||
},
|
||||
);
|
||||
|
||||
my $all_modules = _get_extension_requirements(
|
||||
@ -186,15 +192,6 @@ sub OPTIONAL_MODULES {
|
||||
},
|
||||
|
||||
# Inbound Email
|
||||
{
|
||||
# Email::MIME::Attachment::Stripper can throw an error with
|
||||
# earlier versions.
|
||||
# This also pulls in Email::MIME and Email::Address for us.
|
||||
package => 'Email-MIME-Modifier',
|
||||
module => 'Email::MIME::Modifier',
|
||||
version => '1.43',
|
||||
feature => 'Inbound Email'
|
||||
},
|
||||
{
|
||||
package => 'Email-MIME-Attachment-Stripper',
|
||||
module => 'Email::MIME::Attachment::Stripper',
|
||||
|
@ -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 $method = Bugzilla->params->{'mail_delivery_method'};
|
||||
return if $method eq 'None';
|
||||
|
||||
my ($header, $body) = $msg =~ /(.*?\n)\n(.*)/s ? ($1, $2) : ('', $msg);
|
||||
my $headers;
|
||||
|
||||
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") {
|
||||
my $from = $email->header('From');
|
||||
|
||||
my ($hostname, @args);
|
||||
if ($method eq "Sendmail") {
|
||||
if (ON_WINDOWS) {
|
||||
$Email::Send::Sendmail::SENDMAIL = SENDMAIL_EXE;
|
||||
}
|
||||
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 $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));
|
||||
}
|
||||
|
||||
# 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);
|
||||
}
|
||||
}
|
||||
|
||||
# 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);
|
||||
push(@args, "-f$from") if $from;
|
||||
push(@args, "-ODeliveryMode=deferred")
|
||||
if !Bugzilla->params->{"sendmailnow"};
|
||||
}
|
||||
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');
|
||||
# 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);
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
if ($method eq "SMTP") {
|
||||
push @args, Host => Bugzilla->params->{"smtpserver"},
|
||||
Hello => $hostname;
|
||||
}
|
||||
|
||||
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 {
|
||||
# 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;
|
||||
|
@ -28,14 +28,13 @@
|
||||
mail_delivery_method => "Defines how email is sent, or if it is sent at all.<br>
|
||||
<ul>
|
||||
<li>
|
||||
'sendmail', 'smtp' and 'qmail' are all MTAs.
|
||||
'Sendmail', 'SMTP' and 'Qmail' are all MTAs.
|
||||
You need to install a third-party sendmail replacement if
|
||||
you want to use sendmail on Windows.
|
||||
</li>
|
||||
<li>
|
||||
'testfile' is useful for debugging: all email is stored
|
||||
in 'data/mailer.testfile' instead of being sent. For more
|
||||
information, see the Mail::Mailer manual.
|
||||
'Test' is useful for debugging: all email is stored
|
||||
in 'data/mailer.testfile' instead of being sent.
|
||||
</li>
|
||||
<li>
|
||||
'none' will completely disable email. $terms.Bugzilla continues
|
||||
|
@ -295,6 +295,11 @@
|
||||
[% ELSIF error == "ldap_server_not_defined" %]
|
||||
The LDAP server for authentication has not been defined.
|
||||
|
||||
[% ELSIF error == "mail_send_error" %]
|
||||
There was an error sending mail from '[% mail.header('From') FILTER html %]'
|
||||
to '[% mail.header('To') FILTER html %]':
|
||||
[% msg FILTER html %]
|
||||
|
||||
[% ELSIF error == "missing_bug_id" %]
|
||||
No [% terms.bug %] ID was given.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user