# BEGIN BPS TAGGED BLOCK {{{
-#
+#
# COPYRIGHT:
-#
-# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC
-# <jesse@bestpractical.com>
-#
+#
+# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC
+# <sales@bestpractical.com>
+#
# (Except where explicitly superseded by other copyright notices)
-#
-#
+#
+#
# LICENSE:
-#
+#
# This work is made available to you under the terms of Version 2 of
# the GNU General Public License. A copy of that license should have
# been provided with this software, but in any event can be snarfed
# from www.gnu.org.
-#
+#
# This work is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 or visit their web page on the internet at
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
-#
-#
+#
+#
# CONTRIBUTION SUBMISSION POLICY:
-#
+#
# (The following paragraph is not intended to limit the rights granted
# to you to modify and distribute this software under the terms of
# the GNU General Public License and is only of importance to you if
# you choose to contribute your changes and enhancements to the
# community by submitting them to Best Practical Solutions, LLC.)
-#
+#
# By intentionally submitting any modifications, corrections or
# derivatives to this work, or any other work intended for use with
# Request Tracker, to Best Practical Solutions, LLC, you confirm that
# royalty-free, perpetual, license to use, copy, create derivative
# works based on those contributions, and sublicense and distribute
# those contributions and any derivatives thereof.
-#
+#
# END BPS TAGGED BLOCK }}}
package RT::Interface::Email;
level => $args{'LogLevel'},
message => $args{'Explanation'}
) if $args{'LogLevel'};
+
# the colons are necessary to make ->build include non-standard headers
- my $entity = MIME::Entity->build(
- Type => "multipart/mixed",
- From => $args{'From'},
- Bcc => $args{'Bcc'},
- To => $args{'To'},
- Subject => $args{'Subject'},
- 'Precedence:' => 'bulk',
+ my %entity_args = (
+ Type => "multipart/mixed",
+ From => $args{'From'},
+ Bcc => $args{'Bcc'},
+ To => $args{'To'},
+ Subject => $args{'Subject'},
'X-RT-Loop-Prevention:' => RT->Config->Get('rtname'),
);
+
+ # only set precedence if the sysadmin wants us to
+ if (defined(RT->Config->Get('DefaultErrorMailPrecedence'))) {
+ $entity_args{'Precedence:'} = RT->Config->Get('DefaultErrorMailPrecedence');
+ }
+
+ my $entity = MIME::Entity->build(%entity_args);
SetInReplyTo( Message => $entity, InReplyTo => $args{'MIMEObj'} );
$entity->attach( Data => $args{'Explanation'} . "\n" );
true value, the message will be marked as an autogenerated error, if
possible. Sets Date field of the head to now if it's not set.
+If the C<X-RT-Squelch> header is set to any true value, the mail will
+not be sent. One use is to let extensions easily cancel outgoing mail.
+
Ticket and Transaction arguments are optional. If Transaction is
specified and Ticket is not then ticket of the transaction is
used, but only if the transaction belongs to a ticket.
return -1;
}
+ if ($args{'Entity'}->head->get('X-RT-Squelch')) {
+ $RT::Logger->info( $msgid . " Squelch header found. Not sending." );
+ return -1;
+ }
+
if ( $TransactionObj && !$TicketObj
&& $TransactionObj->ObjectType eq 'RT::Ticket' )
{
my $mail_command = RT->Config->Get('MailCommand');
- if ($mail_command eq 'testfile') {
+ if ($mail_command eq 'testfile' and not $Mail::Mailer::testfile::config{outfile}) {
$Mail::Mailer::testfile::config{outfile} = File::Temp->new;
+ $RT::Logger->info("Storing outgoing emails in $Mail::Mailer::testfile::config{outfile}");
}
# if it is a sub routine, we just return it;
# don't ignore CHLD signal to get proper exit code
local $SIG{'CHLD'} = 'DEFAULT';
- open my $mail, "|$path $args" or die "couldn't execute program: $!";
+ open( my $mail, '|-', "$path $args >/dev/null" )
+ or die "couldn't execute program: $!";
# if something wrong with $mail->print we will get PIPE signal, handle it
local $SIG{'PIPE'} = sub { die "program unexpectedly closed pipe" };
my $msg = "$msgid: `$path $args` exitted with code ". ($?>>8);
$msg = ", interrupted by signal ". ($?&127) if $?&127;
$RT::Logger->error( $msg );
+ die $msg;
}
};
if ( $@ ) {
$RT::Logger->crit( "$msgid: Could not send mail with command `$path $args`: " . $@ );
+ if ( $TicketObj ) {
+ _RecordSendEmailFailure( $TicketObj );
+ }
return 0;
}
}
) } };
unless ( $smtp ) {
$RT::Logger->crit( "Could not connect to SMTP server.");
+ if ($TicketObj) {
+ _RecordSendEmailFailure( $TicketObj );
+ }
return 0;
}
unless ( $status ) {
$RT::Logger->crit( "$msgid: Could not send mail via SMTP." );
+ if ( $TicketObj ) {
+ _RecordSendEmailFailure( $TicketObj );
+ }
return 0;
}
}
unless ( $args{'Entity'}->send( @mailer_args ) ) {
$RT::Logger->crit( "$msgid: Could not send mail." );
+ if ( $TicketObj ) {
+ _RecordSendEmailFailure( $TicketObj );
+ }
return 0;
}
}
return -1;
}
- $mail->head->set( $_ => $args{ $_ } )
+ $mail->head->set( $_ => Encode::encode_utf8( $args{ $_ } ) )
foreach grep defined $args{$_}, qw(To Cc Bcc From);
SetInReplyTo( Message => $mail, InReplyTo => $args{'InReplyTo'} );
@_
);
- my @recipients =
- map lc $_->address,
+ my $current_address = lc $args{'CurrentUser'}->EmailAddress;
+ my $user = $args{'CurrentUser'}->UserObj;
+
+ return
+ grep { $_ ne $current_address
+ && !RT::EmailParser->IsRTAddress( $_ )
+ && !IgnoreCcAddress( $_ )
+ }
+ map lc $user->CanonicalizeEmailAddress( $_->address ),
map Email::Address->parse( $args{'Head'}->get( $_ ) ),
qw(To Cc);
+}
- my @res;
- foreach my $address ( @recipients ) {
- $address = $args{'CurrentUser'}->UserObj->CanonicalizeEmailAddress( $address );
- next if lc $args{'CurrentUser'}->EmailAddress eq $address;
- next if lc $args{'QueueObj'}->CorrespondAddress eq $address;
- next if lc $args{'QueueObj'}->CommentAddress eq $address;
- next if RT::EmailParser->IsRTAddress( $address );
+=head2 IgnoreCcAddress ADDRESS
- push @res, $address;
- }
- return @res;
-}
+Returns true if ADDRESS matches the $IgnoreCcRegexp config variable.
+=cut
+sub IgnoreCcAddress {
+ my $address = shift;
+ if ( my $address_re = RT->Config->Get('IgnoreCcRegexp') ) {
+ return 1 if $address =~ /$address_re/i;
+ }
+ return undef;
+}
=head2 ParseSenderAddressFromHead HEAD
return ( 1, @actions );
}
-eval "require RT::Interface::Email_Vendor";
-die $@ if ( $@ && $@ !~ qr{^Can't locate RT/Interface/Email_Vendor.pm} );
-eval "require RT::Interface::Email_Local";
-die $@ if ( $@ && $@ !~ qr{^Can't locate RT/Interface/Email_Local.pm} );
+sub _RecordSendEmailFailure {
+ my $ticket = shift;
+ if ($ticket) {
+ $ticket->_RecordNote(
+ NoteType => 'SystemError',
+ Content => "Sending the previous mail has failed. Please contact your admin, they can find more details in the logs.",
+ );
+ return 1;
+ }
+ else {
+ $RT::Logger->error( "Can't record send email failure as ticket is missing" );
+ return;
+ }
+}
+
+RT::Base->_ImportOverlays();
1;