[rt-users] Added bounce Detection for RT3
Jesse Vincent
jesse at bestpractical.com
Thu Mar 20 01:17:43 EST 2003
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,
Jesse
On 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 at 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 at cpan.org>
> -
> -package RT::Action::SendEmail;
> -require RT::Action::Generic;
> -
> -use strict;
> -use vars qw/@ISA/;
> - at 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
> -
> -Jesse Vincent <jesse at bestpractical.com> and Tobias Brox <tobix at cpan.org>
> -
> -=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 {
> - my $self = shift;
> -
> - # TODO: this one is broken. What is this email really a reply to?
> - # If it's a reply to an incoming message, we'll need to use the
> - # actual message-id from the appropriate Attachment object. For
> - # incoming mails, we would like to preserve the In-Reply-To and/or
> - # References.
> -
> - $self->SetHeader( 'In-Reply-To',
> - "<rt-" . $self->TicketObj->id() . "\@" . $RT::rtname . ">" );
> -
> - # TODO We should always add References headers for all message-ids
> - # of previous messages related to this ticket.
> -}
> -
> -# }}}
> -
> -# {{{ 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 {
> - my $self = shift;
> -
> - unless ( $self->TemplateObj->MIMEObj->head->get("Precedence") ) {
> - $self->SetHeader( 'Precedence', "bulk" );
> - }
> -}
> -
> -# }}}
> -
> -# {{{ 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 {
> - my $self = shift;
> - my $tag = "[$RT::rtname #" . $self->TicketObj->id . "]";
> - my $sub = $self->TemplateObj->MIMEObj->head->get('Subject');
> - unless ( $sub =~ /\Q$tag\E/ ) {
> - $sub =~ s/(\r\n|\n|\s)/ /gi;
> - chomp $sub;
> - $self->TemplateObj->MIMEObj->head->replace( 'Subject', "$tag $sub" );
> - }
> -}
> -
> -# }}}
> -
> -# }}}
> -
> -# {{{
> -
> -=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
> - my $IsABounce;
> - my @BounceTo = ParseCcAddressesFromHead(Head => $head,
> - CurrentUser => $RT::SystemUser,
> - QueueObj =>$SystemQueueObj );
> -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 ) {
>
--
http://www.bestpractical.com/rt -- Trouble Ticketing. Free.
More information about the rt-users
mailing list