This is excellent. Thanks! I’ll get this up into contrib as soon as I
can manage and we’ll look at folding it or something like it into a
post-3.0 release
Best,
JesseOn Thu, Mar 20, 2003 at 03:47:15PM +1100, Stewart James wrote:
Hi,
Here is my loose bounce detection for rt3. As usual not really tested, but
working for me.
thse are diffs ofr ~rt3/lib/RT/Action/Sendmail.pm and
~rt3/lib/Interface/Email.pm
Add:
Set($BounceDomain, “yourdomain.com”);
to your RT_SiteConfig.pm where yourdomain is where you want your bounces
to go to.
Under sendmail I put an alias
bounce+*: “|/usr/local/rt3/bin/rt-mailgate --queue general --action comment --url http://WEBURL”
THe queue is not important, email sent to people is sent as
bounce+ticket-#@vu.edu.au The system should figure out from that which
ticket to put the message into so the queue is not important.
Also you must add a user ‘bounce’ (I set the real name to Bounced Message
- that way users see “Bounced Message VIA RT”) and give use bounce tha
ability to comment on all tickets globally.
I worked on this while doing other bits and peices so hope I did not
forget any other files I have altered.
I’m not too worried about this but you might: Sendmail will add a warning
that www-data sent mail as bounce+yadayada, I think you can add www-data
to trusted users of senbmail for that to be stopped. I do not mind the
system doing this myself.
If someone tries this and gets it working please let me know. Be aware,
that there is no ‘loop’ detection on this - if a non-requestor is
generating the bounces you will get a loop happening.
Stewart
— Action/SendEmail.pm 2003-03-20 13:26:25.000000000 +1100
+++ /home/stewart/rt3/rt-3-0-0rc3/lib/RT/Action/Sendmail.pm 1970-01-01 10:00:00.000000000 +1000
@@ -1,579 +0,0 @@
-# BEGIN LICENSE BLOCK
-#
-# Copyright (c) 1996-2003 Jesse Vincent jesse@bestpractical.com
-#
-# (Except where explictly superceded by other copyright notices)
-#
-# 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.
-#
-# Unless otherwise specified, all modifications, corrections or
-# extensions to this work which alter its source code become the
-# property of Best Practical Solutions, LLC when submitted for
-# inclusion in the work.
-#
-#
-# END LICENSE BLOCK
-# Portions Copyright 2000 Tobias Brox tobix@cpan.org
-package RT::Action::SendEmail;
-require RT::Action::Generic;
-use strict;
-use vars qw/@ISA/;
-@ISA = qw(RT::Action::Generic);
-use MIME::Words qw(encode_mimeword);
-=head1 NAME
- RT::Action::SendEmail - An Action which users can use to send mail
- or can subclassed for more specialized mail sending behavior.
- RT::Action::AutoReply is a good example subclass.
-=head1 SYNOPSIS
- require RT::Action::SendEmail;
- @ISA = qw(RT::Action::SendEmail);
-=head1 DESCRIPTION
-Basically, you create another module RT::Action::YourAction which ISA
-RT::Action::SendEmail.
-If you want to set the recipients of the mail to something other than
-the addresses mentioned in the To, Cc, Bcc and headers in
-the template, you should subclass RT::Action::SendEmail and override
-either the SetRecipients method or the SetTo, SetCc, etc methods (see
-the comments for the SetRecipients sub).
-=begin testing
-ok (require RT::Action::SendEmail);
-=end testing
-=head1 AUTHOR
-=head1 SEE ALSO
-perl(1).
-=cut
-# {{{ Scrip methods (_Init, Commit, Prepare, IsApplicable)
-# {{{ sub _Init
-# We use _Init from RT::Action
-# }}}
-# {{{ sub Commit
-#Do what we need to do and send it out.
-sub Commit {
- my $self = shift;
- my $MIMEObj = $self->TemplateObj->MIMEObj;
- my $msgid = $MIMEObj->head->get(‘Message-Id’);
- chomp $msgid;
- $RT::Logger->info($msgid." #“.$self->TicketObj->id.”/“.$self->TransactionObj->id.” - Scrip “. $self->ScripObj->id .” ".$self->ScripObj->Description);
- #send the email
-
If there are no recipients, don’t try to send the message.
-
If the transaction has content and has the header RT-Squelch-Replies-To
- if ( defined $self->TransactionObj->Attachments->First() ) {
-
my $squelch = $self->TransactionObj->Attachments->First->GetHeader( 'RT-Squelch-Replies-To');
-
if ($squelch) {
-
my @blacklist = split ( /,/, $squelch );
-
# Cycle through the people we're sending to and pull out anyone on the
-
# system blacklist
-
foreach my $person_to_yank (@blacklist) {
-
$person_to_yank =~ s/\s//g;
-
@{ $self->{'To'} } =
-
grep ( !/^$person_to_yank$/, @{ $self->{'To'} } );
-
@{ $self->{'Cc'} } =
-
grep ( !/^$person_to_yank$/, @{ $self->{'Cc'} } );
-
@{ $self->{'Bcc'} } =
-
grep ( !/^$person_to_yank$/, @{ $self->{'Bcc'} } );
-
}
-
}
- }
-
Go add all the Tos, Ccs and Bccs that we need to to the message to
-
make it happy, but only if we actually have values in those arrays.
- $self->SetHeader( ‘To’, join ( ‘,’, @{ $self->{‘To’} } ) )
-
if ( $self->{'To'} && @{ $self->{'To'} } );
- $self->SetHeader( ‘Cc’, join ( ‘,’, @{ $self->{‘Cc’} } ) )
-
if ( $self->{'Cc'} && @{ $self->{'Cc'} } );
- $self->SetHeader( ‘Bcc’, join ( ‘,’, @{ $self->{‘Bcc’} } ) )
-
if ( $self->{'Cc'} && @{ $self->{'Bcc'} } );
-
try to convert message body from utf-8 to $RT::EmailOutputEncoding
- $self->SetHeader( ‘Content-Type’, ‘text/plain; charset=“utf-8”’ );
- RT::I18N::SetMIMEEntityToEncoding( $MIMEObj, $RT::EmailOutputEncoding );
- $self->SetHeader( ‘Content-Type’,
-
'text/plain; charset="' . $RT::EmailOutputEncoding . '"' );
- $MIMEObj->make_multipart(‘mixed’);
- $self->SetHeader(‘MIME-Version’, ‘1.0’);
-
Build up a MIME::Entity that looks like the original message.
- my $do_attach = $self->TemplateObj->MIMEObj->head->get(‘RT-Attach-Message’);
- if ($do_attach) {
-
my $attachments = RT::Attachments->new($RT::SystemUser);
-
$attachments->Limit( FIELD => 'TransactionId',
-
VALUE => $self->TransactionObj->Id );
-
$attachments->OrderBy('id');
-
my $transaction_content_obj = $self->TransactionObj->ContentObj;
-
# attach any of this transaction's attachments
-
while ( my $attach = $attachments->Next ) {
-
# Don't attach anything blank
-
next unless ( $attach->Content );
-
# We want to make sure that we don't include the attachment that's being sued as the "Content" of this message"
-
next
-
if ( $transaction_content_obj
-
&& $transaction_content_obj->Id == $attach->Id );
-
$MIMEObj->attach( Type => $attach->ContentType,
-
Data => $attach->Content );
-
}
- }
- #If we don’t have any recipients to send to, don’t send a message;
- unless ( $MIMEObj->head->get(‘To’)
-
|| $MIMEObj->head->get('Cc')
-
|| $MIMEObj->head->get('Bcc') ) {
-
$RT::Logger->info($msgid. " No recipients found. Not sending.\n");
-
return (1);
- }
-
PseudoTo (fake to headers) shouldn’t get matched for message recipients.
-
If we don’t have any ‘To’ header, drop in the pseudo-to header.
- $self->SetHeader( ‘To’, join ( ‘,’, @{ $self->{‘PseudoTo’} } ) )
-
if ( $self->{'PseudoTo'} && ( @{ $self->{'PseudoTo'} } )
-
and ( !$MIMEObj->head->get('To') ) );
- my $ReturnPath = “bounce+ticket-” . $self->TicketObj->id . “@$RT::BounceDomain”;
- if ( $RT::MailCommand eq ‘sendmailpipe’ ) {
-
eval {
-
open( MAIL, "|$RT::SendmailPath $RT::SendmailArguments -f$ReturnPath" );
-
print MAIL $MIMEObj->as_string;
-
close(MAIL);
-
};
-
if ($@) {
-
$RT::Logger->crit($msgid. "Could not send mail. -".$@ );
-
}
- }
- else {
-
if ( $RT::MailCommand eq 'sendmail' ) {
-
$RT::MailParams = $RT::SendmailArguments;
-
}
-
unless ( $MIMEObj->send( $RT::MailCommand, $RT::MailParams ) ) {
-
$RT::Logger->crit($msgid. "Could not send mail." );
-
return (0);
-
}
- }
-
my $success = ($msgid. " sent To: ".$MIMEObj->head->get('To') . " Cc: ".$MIMEObj->head->get('Cc') . " Bcc: ".$MIMEObj->head->get('Bcc'));
- $success =~ s/\n//gi;
- $RT::Logger->info($success);
- return (1);
-}
-# }}}
-# {{{ sub Prepare
-sub Prepare {
- my $self = shift;
-
This actually populates the MIME::Entity fields in the Template Object
- unless ( $self->TemplateObj ) {
-
$RT::Logger->warning("No template object handed to $self\n");
- }
- unless ( $self->TransactionObj ) {
-
$RT::Logger->warning("No transaction object handed to $self\n");
- }
- unless ( $self->TicketObj ) {
-
$RT::Logger->warning("No ticket object handed to $self\n");
- }
- my ( $result, $message ) = $self->TemplateObj->Parse(
-
Argument => $self->Argument,
-
TicketObj => $self->TicketObj,
-
TransactionObj => $self->TransactionObj
- );
- if ($result) {
-
# Header
-
$self->SetSubject();
-
$self->SetSubjectToken();
-
$self->SetRecipients();
-
$self->SetReturnAddress();
-
$self->SetRTSpecialHeaders();
-
if ($RT::EmailOutputEncoding) {
-
# l10n related header
-
$self->SetHeaderAsEncoding( 'Subject', $RT::EmailOutputEncoding );
-
$self->SetHeaderAsEncoding( 'From', $RT::EmailOutputEncoding );
-
}
- }
- return $result;
-}
-# }}}
-# }}}
-# {{{ Deal with message headers (Set* subs, designed for easy overriding)
-# {{{ sub SetRTSpecialHeaders
-# This routine adds all the random headers that RT wants in a mail message
-# that don’t matter much to anybody else.
-sub SetRTSpecialHeaders {
- my $self = shift;
- $self->SetReferences();
- $self->SetMessageID();
- $self->SetPrecedence();
- $self->SetHeader( ‘X-RT-Loop-Prevention’, $RT::rtname );
- $self->SetHeader( ‘RT-Ticket’,
-
$RT::rtname . " #" . $self->TicketObj->id() );
- $self->SetHeader( ‘Managed-by’,
-
"RT $RT::VERSION (http://www.bestpractical.com/rt/)" );
- $self->SetHeader( ‘RT-Originator’,
-
$self->TransactionObj->CreatorObj->EmailAddress );
- return ();
-}
-# {{{ sub SetReferences
-=head2 SetReferences
-
This routine will set the References: and In-Reply-To headers,
-# autopopulating it with all the correspondence on this ticket so
-# far. This should make RT responses threadable.
-=cut
-sub SetReferences {
-}
-# }}}
-# {{{ sub SetMessageID
-# Without this one, threading won’t work very nice in email agents.
-# Anyway, I’m not really sure it’s that healthy if we need to send
-# several separate/different emails about the same transaction.
-sub SetMessageID {
- my $self = shift;
-
TODO this one might be sort of broken. If we have several scrips +++
-
sending several emails to several different persons, we need to
-
pull out different message-ids. I’d suggest message ids like
-
“rt-ticket#-transaction#-scrip#-receipient#”
- $self->SetHeader( ‘Message-ID’,
-
"<rt-"
-
. $RT::VERSION ."-"
-
. $self->TicketObj->id() . "-"
-
. $self->TransactionObj->id() . "."
-
. rand(20) . "\@"
-
. $RT::Organization . ">" )
-
unless $self->TemplateObj->MIMEObj->head->get('Message-ID');
-}
-# }}}
-# }}}
-# {{{ sub SetReturnAddress
-sub SetReturnAddress {
- my $self = shift;
- my %args = ( is_comment => 0,
-
@_ );
-
From and Reply-To
-
$args{is_comment} should be set if the comment address is to be used.
- my $replyto;
- if ( $args{‘is_comment’} ) {
-
$replyto = $self->TicketObj->QueueObj->CommentAddress
-
|| $RT::CommentAddress;
- }
- else {
-
$replyto = $self->TicketObj->QueueObj->CorrespondAddress
-
|| $RT::CorrespondAddress;
- }
- unless ( $self->TemplateObj->MIMEObj->head->get(‘From’) ) {
-
my $friendly_name = $self->TransactionObj->CreatorObj->RealName;
-
if ( $friendly_name =~ /^"(.*)"$/ ) { # a quoted string
-
$friendly_name = $1;
-
}
-
$friendly_name =~ s/"/\\"/g;
-
# TODO: this "via RT" should really be site-configurable.
-
$self->SetHeader( 'From', "\"$friendly_name via RT\" <$replyto>" );
- }
- unless ( $self->TemplateObj->MIMEObj->head->get(‘Reply-To’) ) {
-
$self->SetHeader( 'Reply-To', "$replyto" );
- }
-}
-# }}}
-# {{{ sub SetHeader
-sub SetHeader {
- my $self = shift;
- my $field = shift;
- my $val = shift;
- chomp $val;
- chomp $field;
- $self->TemplateObj->MIMEObj->head->fold_length( $field, 10000 );
- $self->TemplateObj->MIMEObj->head->replace( $field, $val );
- return $self->TemplateObj->MIMEObj->head->get($field);
-}
-# }}}
-# {{{ sub SetRecipients
-=head2 SetRecipients
-Dummy method to be overriden by subclasses which want to set the recipients.
-=cut
-sub SetRecipients {
- my $self = shift;
- return ();
-}
-# }}}
-# {{{ sub SetTo
-sub SetTo {
- my $self = shift;
- my $addresses = shift;
- return $self->SetHeader( ‘To’, $addresses );
-}
-# }}}
-# {{{ sub SetCc
-=head2 SetCc
-Takes a string that is the addresses you want to Cc
-=cut
-sub SetCc {
- my $self = shift;
- my $addresses = shift;
- return $self->SetHeader( ‘Cc’, $addresses );
-}
-# }}}
-# {{{ sub SetBcc
-=head2 SetBcc
-Takes a string that is the addresses you want to Bcc
-=cut
-sub SetBcc {
- my $self = shift;
- my $addresses = shift;
- return $self->SetHeader( ‘Bcc’, $addresses );
-}
-# }}}
-# {{{ sub SetPrecedence
-sub SetPrecedence {
-# }}}
-# {{{ sub SetSubject
-=head2 SetSubject
-This routine sets the subject. it does not add the rt tag. that gets done elsewhere
-If $self->{‘Subject’} is already defined, it uses that. otherwise, it tries to get
-the transaction’s subject.
-=cut
-sub SetSubject {
- my $self = shift;
- my $subject;
- unless ( $self->TemplateObj->MIMEObj->head->get(‘Subject’) ) {
-
my $message = $self->TransactionObj->Attachments;
-
my $ticket = $self->TicketObj->Id;
-
if ( $self->{'Subject'} ) {
-
$subject = $self->{'Subject'};
-
}
-
elsif ( ( $message->First() )
-
&& ( $message->First->Headers ) ) {
-
my $header = $message->First->Headers();
-
$header =~ s/\n\s+/ /g;
-
if ( $header =~ /^Subject: (.*?)$/m ) {
-
$subject = $1;
-
}
-
else {
-
$subject = $self->TicketObj->Subject();
-
}
-
}
-
else {
-
$subject = $self->TicketObj->Subject();
-
}
-
$subject =~ s/(\r\n|\n|\s)/ /gi;
-
chomp $subject;
-
$self->SetHeader( 'Subject', $subject );
- }
- return ($subject);
-}
-# }}}
-# {{{ sub SetSubjectToken
-=head2 SetSubjectToken
- This routine fixes the RT tag in the subject. It’s unlikely that you want to overwrite this.
-=cut
-sub SetSubjectToken {
-# }}}
-# }}}
-# {{{
-=head 2 SetHeaderAsEncoding($field_name, $charset_encoding)
- This routine converts the field into specified charset encoding.
-=cut
-sub SetHeaderAsEncoding {
- my $self = shift;
- my ( $field, $enc ) = ( shift, shift );
- my $value = $self->TemplateObj->MIMEObj->head->get($field);
-
don’t bother if it’s us-ascii
- chomp $value;
- return unless $value =~ /[^\x20-\x7e]/;
- $value =~ s/\s*$//;
-
See RT::I18N, ‘NOTES: Why Encode::_utf8_off before Encode::from_to’
- Encode::_utf8_off($value);
- my $res = Encode::from_to( $value, “utf-8”, $enc );
- $value = encode_mimeword( $value, ‘b’, $enc );
- $self->TemplateObj->MIMEObj->head->replace( $field, $value );
-}
-# }}}
-eval “require RT::Action::SendEmail_Local”;
-die $@ if ($@ && $@ !~ qr{^Can’t locate RT/Action/SendEmail_Local.pm});
-1;
— Interface/Email.pm 2003-03-20 13:41:31.000000000 +1100
+++ /home/stewart/rt3/rt-3-0-0rc3/lib/RT/Interface/Email.pm 2003-03-19 17:01:32.000000000 +1100
@@ -424,17 +424,6 @@
my $SystemQueueObj = RT::Queue->new($RT::SystemUser);
$SystemQueueObj->Load( $args{‘queue’} );
-#SJ HACK ON BOUNCING
-if ($BounceTo[0] =~/bounce+/) {
-
my $SJTicketId = $BounceTo[0];
-
$SJTicketId =~ s/bounce\+ticket-(\d+)@.*/$1/ ;
-
$args{'ticket'} = $SJTicketId;
-
$IsABounce = 1;
-
}
We can safely have no queue of we have a known-good ticket
unless ( $args{‘ticket’} || $SystemQueueObj->id ) {
@@ -452,15 +441,6 @@
1 - Normal user
2 - User is allowed to specify status updates etc. a la enhanced-mailgate
-#SJ HACK
- if ($IsABounce) {
-
$RT::Logger->crit("LOADING BOUNCE USER");
-
$CurrentUser = RT::CurrentUser->new();
-
$CurrentUser->LoadByName('bounce');
-
$AuthStat=1;
-} else {
- push @RT::MailPlugins, “Auth::MailFrom” unless @RT::MailPlugins;
Since this needs loading, no matter what
@@ -495,7 +475,7 @@
last if $AuthStat == -1;
$AuthStat = $NewAuthStat if $NewAuthStat > $AuthStat;
}
-}
+
# {{{ If authentication fails and no new user was created, get out.
if ( !$CurrentUser or !$CurrentUser->Id or $AuthStat == -1 ) {
Request Tracker... So much more than a help desk — Best Practical Solutions – Trouble Ticketing. Free.