#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
my ( $From, $junk ) = ParseSenderAddressFromHead($head);
+ # If unparseable (non-ASCII), $From can come back undef
+ return undef if not defined $From;
+
if ( ( $From =~ /^mailer-daemon\@/i )
or ( $From =~ /^postmaster\@/i )
or ( $From eq "" ))
=item Attach - optional text that attached to the error as 'message/rfc822' part.
-=item LogLevel - log level under which we should write explanation message into the
-log, by default we log it as critical.
+=item LogLevel - log level under which we should write the subject and
+explanation message into the log, by default we log it as critical.
=back
$RT::Logger->log(
level => $args{'LogLevel'},
- message => $args{'Explanation'}
+ message => "$args{Subject}: $args{'Explanation'}",
) if $args{'LogLevel'};
# the colons are necessary to make ->build include non-standard headers
# SetOutgoingMailFrom and bounces conflict, since they both want -f
if ( $args{'Bounce'} ) {
push @args, shellwords(RT->Config->Get('SendmailBounceArguments'));
- } elsif ( RT->Config->Get('SetOutgoingMailFrom') ) {
- my $OutgoingMailAddress;
+ } elsif ( my $MailFrom = RT->Config->Get('SetOutgoingMailFrom') ) {
+ my $OutgoingMailAddress = $MailFrom =~ /\@/ ? $MailFrom : undef;
+ my $Overrides = RT->Config->Get('OverrideOutgoingMailFrom') || {};
if ($TicketObj) {
my $QueueName = $TicketObj->QueueObj->Name;
- my $QueueAddressOverride = RT->Config->Get('OverrideOutgoingMailFrom')->{$QueueName};
+ my $QueueAddressOverride = $Overrides->{$QueueName};
if ($QueueAddressOverride) {
$OutgoingMailAddress = $QueueAddressOverride;
} else {
- $OutgoingMailAddress = $TicketObj->QueueObj->CorrespondAddress;
+ $OutgoingMailAddress ||= $TicketObj->QueueObj->CorrespondAddress
+ || RT->Config->Get('CorrespondAddress');
}
}
-
- $OutgoingMailAddress ||= RT->Config->Get('OverrideOutgoingMailFrom')->{'Default'};
+ elsif ($Overrides->{'Default'}) {
+ $OutgoingMailAddress = $Overrides->{'Default'};
+ }
push @args, "-f", $OutgoingMailAddress
if $OutgoingMailAddress;
Takes a hash containing QueueObj, Head and CurrentUser objects.
Returns a list of all email addresses in the To and Cc
-headers b<except> the current Queue\'s email addresses, the CurrentUser\'s
+headers b<except> the current Queue's email addresses, the CurrentUser's
email address and anything that the configuration sub RT::IsRTAddress matches.
=cut
&& !IgnoreCcAddress( $_ )
}
map lc $user->CanonicalizeEmailAddress( $_->address ),
- map Email::Address->parse( $args{'Head'}->get( $_ ) ),
+ map RT::EmailParser->CleanupAddresses( Email::Address->parse( $args{'Head'}->get( $_ ) ) ),
qw(To Cc);
}
=head2 ParseSenderAddressFromHead HEAD
-Takes a MIME::Header object. Returns a tuple: (user@host, friendly name)
-of the From (evaluated in order of Reply-To:, From:, Sender)
+Takes a MIME::Header object. Returns (user@host, friendly name, errors)
+where the first two values are the From (evaluated in order of
+Reply-To:, From:, Sender).
+
+A list of error messages may be returned even when a Sender value is
+found, since it could be a parse error for another (checked earlier)
+sender field. In this case, the errors aren't fatal, but may be useful
+to investigate the parse failure.
=cut
sub ParseSenderAddressFromHead {
my $head = shift;
+ my @sender_headers = ('Reply-To', 'From', 'Sender');
+ my @errors; # Accumulate any errors
#Figure out who's sending this message.
- foreach my $header ('Reply-To', 'From', 'Sender') {
+ foreach my $header ( @sender_headers ) {
my $addr_line = $head->get($header) || next;
my ($addr, $name) = ParseAddressFromHeader( $addr_line );
# only return if the address is not empty
- return ($addr, $name) if $addr;
+ return ($addr, $name, @errors) if $addr;
+
+ chomp $addr_line;
+ push @errors, "$header: $addr_line";
}
- return (undef, undef);
+ return (undef, undef, @errors);
}
=head2 ParseErrorsToAddressFromHead HEAD
}
@mail_plugins = grep !$skip_plugin{"$_"}, @mail_plugins;
$parser->_DecodeBodies;
+ $parser->RescueOutlook;
$parser->_PostProcessNewEntity;
my $head = $Message->head;
my $ErrorsTo = ParseErrorsToAddressFromHead( $head );
+ my $Sender = (ParseSenderAddressFromHead( $head ))[0];
+ my $From = $head->get("From");
+ chomp $From if defined $From;
my $MessageId = $head->get('Message-ID')
|| "<no-message-id-". time . rand(2000) .'@'. RT->Config->Get('Organization') .'>';
$args{'ticket'} ||= ExtractTicketId( $Message );
+ # ExtractTicketId may have been overridden, and edited the Subject
+ my $NewSubject = $Message->head->get('Subject');
+ chomp $NewSubject;
+
$SystemTicket = RT::Ticket->new( RT->SystemUser );
$SystemTicket->Load( $args{'ticket'} ) if ( $args{'ticket'} ) ;
if ( $SystemTicket->id ) {
);
return (
0,
- "$ErrorsTo tried to submit a message to "
+ ($CurrentUser->EmailAddress || $CurrentUser->Name)
+ . " ($Sender) tried to submit a message to "
. $args{'Queue'}
. " without permission.",
undef
);
}
+ $head->replace('X-RT-Interface' => 'Email');
+
my ( $id, $Transaction, $ErrStr ) = $Ticket->Create(
Queue => $SystemQueueObj->Id,
- Subject => $Subject,
+ Subject => $NewSubject,
Requestor => \@Requestors,
Cc => \@Cc,
MIMEObj => $Message
Explanation => $ErrStr,
MIMEObj => $Message
);
- return ( 0, "Ticket creation failed: $ErrStr", $Ticket );
+ return ( 0, "Ticket creation From: $From failed: $ErrStr", $Ticket );
}
# strip comments&corresponds from the actions we don't need
#Warn the sender that we couldn't actually submit the comment.
MailError(
To => $ErrorsTo,
- Subject => "Message not recorded: $Subject",
+ Subject => "Message not recorded ($method): $Subject",
Explanation => $msg,
MIMEObj => $Message
);
- return ( 0, "Message not recorded: $msg", $Ticket );
+ return ( 0, "Message From: $From not recorded: $msg", $Ticket );
}
} elsif ($unsafe_actions) {
my ( $status, $msg ) = _RunUnsafeAction(
@_
);
+ my $From = $args{Message}->head->get("From");
+
if ( $args{'Action'} =~ /^take$/i ) {
my ( $status, $msg ) = $args{'Ticket'}->SetOwner( $args{'CurrentUser'}->id );
unless ($status) {
Explanation => $msg,
MIMEObj => $args{'Message'}
);
- return ( 0, "Ticket not taken" );
+ return ( 0, "Ticket not taken, by email From: $From" );
}
} elsif ( $args{'Action'} =~ /^resolve$/i ) {
my $new_status = $args{'Ticket'}->FirstInactiveStatus;
Explanation => $msg,
MIMEObj => $args{'Message'}
);
- return ( 0, "Ticket not resolved" );
+ return ( 0, "Ticket not resolved, by email From: $From" );
}
}
} else {
- return ( 0, "Not supported unsafe action $args{'Action'}", $args{'Ticket'} );
+ return ( 0, "Not supported unsafe action $args{'Action'}, by email From: $From", $args{'Ticket'} );
}
return ( 1, "Success" );
}