<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://rt-wiki.bestpractical.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Medea61</id>
	<title>Request Tracker Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://rt-wiki.bestpractical.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Medea61"/>
	<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/wiki/Special:Contributions/Medea61"/>
	<updated>2026-08-22T17:39:14Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.1</generator>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=WriteCustomAction&amp;diff=26291</id>
		<title>WriteCustomAction</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=WriteCustomAction&amp;diff=26291"/>
		<updated>2016-07-19T17:15:10Z</updated>

		<summary type="html">&lt;p&gt;Medea61: /* Step by step or &amp;quot;Tickets, transactions and attachments&amp;quot; */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This text in Portuguese in [[WriteCustomActionBR]]&lt;br /&gt;
&lt;br /&gt;
How to write custom action code&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Included in RT3 is the ability to create your own custom ticket actions via the Web UI. The RT3 Custom Scrip capability lets you access the RT API and is a very powerful tool for customising RT.&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
[[File:Example1ScripUI.png|thumb|left|325px|Modify a scrip UI]]Let&#039;s start with Web UI. Goto Configuration -&amp;amp;gt; Globals -&amp;amp;gt; Scrips -&amp;amp;gt; New Scrip.&lt;br /&gt;
&lt;br /&gt;
The Scrip UI will display the following selectors: Description, Condition, Action, Template and Stage. In the action selector you can pick actions based on files (modules). An outstanding action from this list is &amp;quot;User Defined&amp;quot;. The rest of this document describes this action. So in the Action field, select &amp;quot;User Defined&amp;quot; from the menu.&lt;br /&gt;
&lt;br /&gt;
Once you have selected &amp;quot;User Defined&amp;quot; from the Action Field, the following two Action code areas are enabled and used by RT:&lt;br /&gt;
* Custom action preparation code&lt;br /&gt;
* Custom action cleanup code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When a [[Transaction]] is created, RT does the following steps to enable all this magic and give you a chance to be a small God:&lt;br /&gt;
&lt;br /&gt;
* Select [[Scrip|Scrips]]&lt;br /&gt;
* Check applicability of scrips by executing [[Condition]]s&lt;br /&gt;
* Execute preparation code scrip by scrip&lt;br /&gt;
* Scrips that fail will be thrown away&lt;br /&gt;
* Execute commit code of survived scrips proceeding scrip by scrip&lt;br /&gt;
&lt;br /&gt;
When RT executes your perl Action code within this scrip, your code can become an actor upon the ticket. RT has already defined the variable $self. This variable represents an instance of class [=RT::Action::[[UserDefined]]], a subclass of &amp;lt;code&amp;gt;RT::Action::Generic&amp;lt;/code&amp;gt;. You can get more info from perldoc and from the source code.&lt;br /&gt;
&lt;br /&gt;
Instance &amp;lt;code&amp;gt;$self&amp;lt;/code&amp;gt; provides your Action code with very useful methods:&lt;br /&gt;
&lt;br /&gt;
 $self-&amp;amp;gt;TransactionObj&lt;br /&gt;
&lt;br /&gt;
Returns &amp;lt;code&amp;gt;RT::Transaction&amp;lt;/code&amp;gt; instance, the transaction that has been created and caused all this.&lt;br /&gt;
&lt;br /&gt;
 $self-&amp;amp;gt;TicketObj&lt;br /&gt;
&lt;br /&gt;
Returns &amp;lt;code&amp;gt;RT::Ticket&amp;lt;/code&amp;gt; instance which represents the ticket. Our transaction was applied to it.&lt;br /&gt;
&lt;br /&gt;
 $self-&amp;amp;gt;TemplateObj&lt;br /&gt;
&lt;br /&gt;
Returns the template (&amp;lt;code&amp;gt;RT::Template&amp;lt;/code&amp;gt;) which was selected for this scrip.&lt;br /&gt;
&lt;br /&gt;
=== Getting more info about these objects ===&lt;br /&gt;
&lt;br /&gt;
You can get complete information about these objects from their POD (embedded documentation).&lt;br /&gt;
&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Ticket.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Ticket_Overlay.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Tickets.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Tickets_Overlay.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Transaction.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Transaction_Overlay.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Transactions.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Transactions_Overlay.pm&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
== Simple example ==&lt;br /&gt;
&lt;br /&gt;
Ok, let&#039;s try to change something.&lt;br /&gt;
&lt;br /&gt;
Requirement: There is a support queue for special customers where each request must have high priority on ticket creation.&lt;br /&gt;
&lt;br /&gt;
[[File:Example1ScripBehavior.png|thumb|275px]]Preparation code:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
     # we don&#039;t need any preparation yet.&lt;br /&gt;
     return 1;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Commit code:&lt;br /&gt;
&lt;br /&gt;
 $self-&amp;amp;gt;TicketObj-&amp;amp;gt;SetPriority( 100 );&lt;br /&gt;
 return 1;&lt;br /&gt;
&lt;br /&gt;
I hope that this example is understandable enough, but it has at least one weakness. I&#039;ve hardcoded the priority value. Since RT lets the administrator define default final priority per queue, our code should reflect that.&lt;br /&gt;
&lt;br /&gt;
 my $qfp = $self-&amp;amp;gt;TicketObj-&amp;amp;gt;QueueObj-&amp;amp;gt;FinalPriority || 100;&lt;br /&gt;
 $self-&amp;amp;gt;TicketObj-&amp;amp;gt;SetPriority( int( $qfp * 0.9 ) );&lt;br /&gt;
 return 1;&lt;br /&gt;
&lt;br /&gt;
This change to the logic first retrieves the [[FinalPriority]] of the current Queue or 100 if no [[FinalPriority]] is set for the Queue. Then it sets the Priority of this ticket to 90% of the retrieved Priority. The final 10% of the priority is reserved for very exclusive, super high priority requests.&lt;br /&gt;
&lt;br /&gt;
== Errors handling ==&lt;br /&gt;
&lt;br /&gt;
It&#039;s important to check errors to protect you from headache. Most methods in RT that change something return a tuple ($status, $msg). If $status is not true value then something failed and $msg is error text describing the reason. Let&#039;s extend our code:&lt;br /&gt;
&lt;br /&gt;
 my $qfp = $self-&amp;amp;gt;TicketObj-&amp;amp;gt;QueueObj-&amp;amp;gt;FinalPriority || 100;&lt;br /&gt;
 my ($status, $msg) = $self-&amp;amp;gt;TicketObj-&amp;amp;gt;SetPriority( int( $qfp * 0.9 ) );&lt;br /&gt;
 unless ( $status ) {&lt;br /&gt;
     $RT::Logger-&amp;amp;gt;error(&amp;quot;Couldn&#039;t change priority: $msg&amp;quot;);&lt;br /&gt;
     return 0;&lt;br /&gt;
 }&lt;br /&gt;
 return 1;&lt;br /&gt;
&lt;br /&gt;
== What you can (not) do with scrips ==&lt;br /&gt;
&lt;br /&gt;
You can manipulate almost any object in RT within a scrip.&lt;br /&gt;
&lt;br /&gt;
* update properties of tickets, for example set properties of tickets with commands in email&lt;br /&gt;
* change linked tickets, for example [[OpenTicketOnAllMemberResolve]] and [[OpenDependantsOnResolve]]&lt;br /&gt;
* extract info from messages, implement own workflow, create approvals and many-many more actions&lt;br /&gt;
&lt;br /&gt;
Let&#039;s talk about impossible things you don&#039;t even want to try to do with a scrip:&lt;br /&gt;
&lt;br /&gt;
* you couldn&#039;t deny action scrip&#039;s triggered, for example you don&#039;t want to allow users to open ticket unless it has owner, you may think that you can create scrip &amp;quot;on ticket open block action if ticket has no owner&amp;quot;, but it&#039;s impossible. I said impossible? no... sure you can create such scrip, but instead of preventing action you can revert it by setting status back to old value. yeah, this works but don&#039;t forget that it would be two transactions &#039;set open status&#039; and &#039;set previouse status&#039;. Each action could be applied to other scrips, so really it&#039;s not preventing action.&lt;br /&gt;
* you couldn&#039;t run scrip at some time, remember RT runs scrips after creating transactions, but of course we have solution for this situation - rt-crontool.&lt;br /&gt;
&lt;br /&gt;
== How to be silent ==&lt;br /&gt;
&lt;br /&gt;
Now you put SetXxxx calls all over the places in RT and suddenly note that strange transactions appear in tickets. They have creator [[RT System|RT_System]] and describe what you&#039;ve done with your scrips. Sometimes it&#039;s better to be silent and not mislead users. These transactions also go through the steps described earlier and could trigger some conditions too. Just use the long form of SetXxx functions:&lt;br /&gt;
&lt;br /&gt;
 $TicketObj-&amp;amp;gt;_Set(Field =&amp;amp;gt; &#039;Priority&#039;, Value =&amp;amp;gt; 90, RecordTransaction =&amp;amp;gt; 0);&lt;br /&gt;
&lt;br /&gt;
The zero in the [[RecordTransaction]] argument informs RT not to record the change as a new transaction.&lt;br /&gt;
&lt;br /&gt;
== How to change ticket custom field values ==&lt;br /&gt;
&lt;br /&gt;
Step 1, get the custom field (CF) object or ID. Don&#039;t use the hardcoded CF ID from the database. [why?] Step 2, get the CF object by ticket object by ticket object (I hope you remember how to get a ticket object) and CF name.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
      my $CFName = &#039;MyCustomField&#039;;&lt;br /&gt;
      my $CF = RT::CustomField-&amp;amp;gt;new( $RT::SystemUser );&lt;br /&gt;
      $CF-&amp;amp;gt;LoadByNameAndQueue( Name =&amp;amp;gt; $CFName, Queue =&amp;amp;gt; $Ticket-&amp;amp;gt;Queue );&lt;br /&gt;
      # RT has bug/feature until 3.0.10, you should load global CF yourself&lt;br /&gt;
      unless( $CF-&amp;amp;gt;id ) {&lt;br /&gt;
        # queue 0 is special case and is a synonym for global queue&lt;br /&gt;
        $CF-&amp;amp;gt;LoadByNameAndQueue( Name =&amp;amp;gt; $CFName, Queue =&amp;amp;gt; &#039;0&#039; );&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      unless( $CF-&amp;amp;gt;id ) {&lt;br /&gt;
        $RT::Logger-&amp;amp;gt;error( &amp;quot;No field $CFName in queue &amp;quot;. $Ticket-&amp;amp;gt;QueueObj-&amp;amp;gt;Name );&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
      ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we could add value to ticket:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 my $Value = &#039;MyValue&#039;;&lt;br /&gt;
 $Ticket-&amp;amp;gt;AddCustomFieldValue( Field =&amp;amp;gt; $CF, Value =&amp;amp;gt; $Value );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 $Ticket-&amp;amp;gt;AddCustomFieldValue( Field =&amp;amp;gt; $CF, Value =&amp;amp;gt; $Value, RecordTransaction =&amp;amp;gt; 0 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
you also could use custom field id instead of object.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 $Ticket-&amp;amp;gt;AddCustomFieldValue( Field =&amp;amp;gt; NN , Value =&amp;amp;gt; $Value );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Step by step or &amp;quot;Tickets, transactions and attachments&amp;quot; ==&lt;br /&gt;
&lt;br /&gt;
Lets look what happens with RT from the beginning when a user clicks on create button in their browser. Web server gets request with queue id, ticket subject and body, owner and etc. RT fetches info from the request that is needed for Ticket record: its Queue id, Status, Subject, [[CurrentUser]](Creator), and then runs the next code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     # init empty instance of RT::Ticket class&lt;br /&gt;
     my $TicketObj = RT::Ticket-&amp;amp;gt;new( $session{&#039;CurrentUser&#039;} );&lt;br /&gt;
     &lt;br /&gt;
     # create new record&lt;br /&gt;
     # if you more familiar with SQL then it&#039;s INSERT&lt;br /&gt;
     # this call is inherited from SearchBuilder API&lt;br /&gt;
     my $id = $TicketObj-&amp;amp;gt;Create( %ARGS );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ticket is created and it&#039;s time to record transaction into table. RT has all info for this: ticket&#039;s id that was recently created and transaction type - &#039;Create&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     # this call creates new transaction record&lt;br /&gt;
     # this is very similar to situation with new ticket record&lt;br /&gt;
     my $TransactionObj = $Ticket-&amp;amp;gt;_RecordTransaction( %ARGS );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Transactions in RT has an many-to-one mapping with ticket. One ticket =&amp;amp;gt; one or more transactions. You can get collection of transactions by calling Transactions method on a ticket object:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 my $transactions = $TicketObj-&amp;amp;gt;Transactions;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each transaction belongs to only one ticket and you get ticket object with the following code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 my $ticket = $TransactionObj-&amp;amp;gt;TicketObj;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
As you can see RT still didn&#039;t use content that you wrote in the body. Content is an RT::Attachment object. You know how RT creates new record and know about Ticket-Transaction relation, the same relationship applies to Attachments and Transactions.&lt;br /&gt;
&lt;br /&gt;
== From &amp;quot;User Defined&amp;quot; to a module ==&lt;br /&gt;
&lt;br /&gt;
User defined actions you write in the web UI are handy and quick way to write an action. However, at some point you want to re-use your action, make it configurable, edit it in more suitable editor rather than text area, make it more complex and consist of additional methods. So it&#039;s time to move from &amp;quot;User Defined&amp;quot; action to your first module file.&lt;br /&gt;
&lt;br /&gt;
 use strict;&lt;br /&gt;
 use warnings;&lt;br /&gt;
 &lt;br /&gt;
 package RT::Action::MyAction;&lt;br /&gt;
 use base qw(RT::Action::Generic);&lt;br /&gt;
 &lt;br /&gt;
 sub Prepare {&lt;br /&gt;
   my $self = shift;&lt;br /&gt;
 &lt;br /&gt;
   ... here goes preparation code ...&lt;br /&gt;
 &lt;br /&gt;
   return 1;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 sub Commit {&lt;br /&gt;
   my $self = shift;&lt;br /&gt;
 &lt;br /&gt;
   ... here goes commit code ...&lt;br /&gt;
 &lt;br /&gt;
   return 1;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 1;&lt;br /&gt;
&lt;br /&gt;
That&#039;s it. Save it as [=lib/RT/Action/MyAction.pm](it is important that the file have the same name as the package (&amp;quot;MyAction&amp;quot; in the example)), fill in preparation and commit code then you can register your action in the DB. Use the following data file and [[AddDatabaseRecords]] instructions.&lt;br /&gt;
&lt;br /&gt;
 @ScripActions = (&lt;br /&gt;
   {&lt;br /&gt;
     Name        =&amp;amp;gt; &#039;My super duper action&#039;,&lt;br /&gt;
     Description =&amp;amp;gt; &#039;Super-puper action that does hell of a job&#039; ,&lt;br /&gt;
     ExecModule =&amp;amp;gt; &#039;MyAction&#039;,&lt;br /&gt;
     Argument   =&amp;amp;gt; &#039;some argument if needed&#039;&lt;br /&gt;
   },&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Now your action in the DB and you can pick it for a scrip through the Web UI instead of picking &amp;quot;User Defined&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
Other documentation on this wiki that may help&lt;br /&gt;
&lt;br /&gt;
[[GlobalObjects]], [[ObjectModel]]&lt;br /&gt;
&lt;br /&gt;
== Special thanks ==&lt;br /&gt;
&lt;br /&gt;
* [[TimWilson]], who was the main editor and reviewer&lt;/div&gt;</summary>
		<author><name>Medea61</name></author>
	</entry>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=WriteCustomAction&amp;diff=26290</id>
		<title>WriteCustomAction</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=WriteCustomAction&amp;diff=26290"/>
		<updated>2016-07-19T17:13:41Z</updated>

		<summary type="html">&lt;p&gt;Medea61: /* How to change ticket custom field values */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This text in Portuguese in [[WriteCustomActionBR]]&lt;br /&gt;
&lt;br /&gt;
How to write custom action code&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Included in RT3 is the ability to create your own custom ticket actions via the Web UI. The RT3 Custom Scrip capability lets you access the RT API and is a very powerful tool for customising RT.&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
[[File:Example1ScripUI.png|thumb|left|325px|Modify a scrip UI]]Let&#039;s start with Web UI. Goto Configuration -&amp;amp;gt; Globals -&amp;amp;gt; Scrips -&amp;amp;gt; New Scrip.&lt;br /&gt;
&lt;br /&gt;
The Scrip UI will display the following selectors: Description, Condition, Action, Template and Stage. In the action selector you can pick actions based on files (modules). An outstanding action from this list is &amp;quot;User Defined&amp;quot;. The rest of this document describes this action. So in the Action field, select &amp;quot;User Defined&amp;quot; from the menu.&lt;br /&gt;
&lt;br /&gt;
Once you have selected &amp;quot;User Defined&amp;quot; from the Action Field, the following two Action code areas are enabled and used by RT:&lt;br /&gt;
* Custom action preparation code&lt;br /&gt;
* Custom action cleanup code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When a [[Transaction]] is created, RT does the following steps to enable all this magic and give you a chance to be a small God:&lt;br /&gt;
&lt;br /&gt;
* Select [[Scrip|Scrips]]&lt;br /&gt;
* Check applicability of scrips by executing [[Condition]]s&lt;br /&gt;
* Execute preparation code scrip by scrip&lt;br /&gt;
* Scrips that fail will be thrown away&lt;br /&gt;
* Execute commit code of survived scrips proceeding scrip by scrip&lt;br /&gt;
&lt;br /&gt;
When RT executes your perl Action code within this scrip, your code can become an actor upon the ticket. RT has already defined the variable $self. This variable represents an instance of class [=RT::Action::[[UserDefined]]], a subclass of &amp;lt;code&amp;gt;RT::Action::Generic&amp;lt;/code&amp;gt;. You can get more info from perldoc and from the source code.&lt;br /&gt;
&lt;br /&gt;
Instance &amp;lt;code&amp;gt;$self&amp;lt;/code&amp;gt; provides your Action code with very useful methods:&lt;br /&gt;
&lt;br /&gt;
 $self-&amp;amp;gt;TransactionObj&lt;br /&gt;
&lt;br /&gt;
Returns &amp;lt;code&amp;gt;RT::Transaction&amp;lt;/code&amp;gt; instance, the transaction that has been created and caused all this.&lt;br /&gt;
&lt;br /&gt;
 $self-&amp;amp;gt;TicketObj&lt;br /&gt;
&lt;br /&gt;
Returns &amp;lt;code&amp;gt;RT::Ticket&amp;lt;/code&amp;gt; instance which represents the ticket. Our transaction was applied to it.&lt;br /&gt;
&lt;br /&gt;
 $self-&amp;amp;gt;TemplateObj&lt;br /&gt;
&lt;br /&gt;
Returns the template (&amp;lt;code&amp;gt;RT::Template&amp;lt;/code&amp;gt;) which was selected for this scrip.&lt;br /&gt;
&lt;br /&gt;
=== Getting more info about these objects ===&lt;br /&gt;
&lt;br /&gt;
You can get complete information about these objects from their POD (embedded documentation).&lt;br /&gt;
&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Ticket.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Ticket_Overlay.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Tickets.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Tickets_Overlay.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Transaction.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Transaction_Overlay.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Transactions.pm&lt;br /&gt;
 perldoc /opt/rt3/lib/RT/Transactions_Overlay.pm&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
== Simple example ==&lt;br /&gt;
&lt;br /&gt;
Ok, let&#039;s try to change something.&lt;br /&gt;
&lt;br /&gt;
Requirement: There is a support queue for special customers where each request must have high priority on ticket creation.&lt;br /&gt;
&lt;br /&gt;
[[File:Example1ScripBehavior.png|thumb|275px]]Preparation code:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
     # we don&#039;t need any preparation yet.&lt;br /&gt;
     return 1;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Commit code:&lt;br /&gt;
&lt;br /&gt;
 $self-&amp;amp;gt;TicketObj-&amp;amp;gt;SetPriority( 100 );&lt;br /&gt;
 return 1;&lt;br /&gt;
&lt;br /&gt;
I hope that this example is understandable enough, but it has at least one weakness. I&#039;ve hardcoded the priority value. Since RT lets the administrator define default final priority per queue, our code should reflect that.&lt;br /&gt;
&lt;br /&gt;
 my $qfp = $self-&amp;amp;gt;TicketObj-&amp;amp;gt;QueueObj-&amp;amp;gt;FinalPriority || 100;&lt;br /&gt;
 $self-&amp;amp;gt;TicketObj-&amp;amp;gt;SetPriority( int( $qfp * 0.9 ) );&lt;br /&gt;
 return 1;&lt;br /&gt;
&lt;br /&gt;
This change to the logic first retrieves the [[FinalPriority]] of the current Queue or 100 if no [[FinalPriority]] is set for the Queue. Then it sets the Priority of this ticket to 90% of the retrieved Priority. The final 10% of the priority is reserved for very exclusive, super high priority requests.&lt;br /&gt;
&lt;br /&gt;
== Errors handling ==&lt;br /&gt;
&lt;br /&gt;
It&#039;s important to check errors to protect you from headache. Most methods in RT that change something return a tuple ($status, $msg). If $status is not true value then something failed and $msg is error text describing the reason. Let&#039;s extend our code:&lt;br /&gt;
&lt;br /&gt;
 my $qfp = $self-&amp;amp;gt;TicketObj-&amp;amp;gt;QueueObj-&amp;amp;gt;FinalPriority || 100;&lt;br /&gt;
 my ($status, $msg) = $self-&amp;amp;gt;TicketObj-&amp;amp;gt;SetPriority( int( $qfp * 0.9 ) );&lt;br /&gt;
 unless ( $status ) {&lt;br /&gt;
     $RT::Logger-&amp;amp;gt;error(&amp;quot;Couldn&#039;t change priority: $msg&amp;quot;);&lt;br /&gt;
     return 0;&lt;br /&gt;
 }&lt;br /&gt;
 return 1;&lt;br /&gt;
&lt;br /&gt;
== What you can (not) do with scrips ==&lt;br /&gt;
&lt;br /&gt;
You can manipulate almost any object in RT within a scrip.&lt;br /&gt;
&lt;br /&gt;
* update properties of tickets, for example set properties of tickets with commands in email&lt;br /&gt;
* change linked tickets, for example [[OpenTicketOnAllMemberResolve]] and [[OpenDependantsOnResolve]]&lt;br /&gt;
* extract info from messages, implement own workflow, create approvals and many-many more actions&lt;br /&gt;
&lt;br /&gt;
Let&#039;s talk about impossible things you don&#039;t even want to try to do with a scrip:&lt;br /&gt;
&lt;br /&gt;
* you couldn&#039;t deny action scrip&#039;s triggered, for example you don&#039;t want to allow users to open ticket unless it has owner, you may think that you can create scrip &amp;quot;on ticket open block action if ticket has no owner&amp;quot;, but it&#039;s impossible. I said impossible? no... sure you can create such scrip, but instead of preventing action you can revert it by setting status back to old value. yeah, this works but don&#039;t forget that it would be two transactions &#039;set open status&#039; and &#039;set previouse status&#039;. Each action could be applied to other scrips, so really it&#039;s not preventing action.&lt;br /&gt;
* you couldn&#039;t run scrip at some time, remember RT runs scrips after creating transactions, but of course we have solution for this situation - rt-crontool.&lt;br /&gt;
&lt;br /&gt;
== How to be silent ==&lt;br /&gt;
&lt;br /&gt;
Now you put SetXxxx calls all over the places in RT and suddenly note that strange transactions appear in tickets. They have creator [[RT System|RT_System]] and describe what you&#039;ve done with your scrips. Sometimes it&#039;s better to be silent and not mislead users. These transactions also go through the steps described earlier and could trigger some conditions too. Just use the long form of SetXxx functions:&lt;br /&gt;
&lt;br /&gt;
 $TicketObj-&amp;amp;gt;_Set(Field =&amp;amp;gt; &#039;Priority&#039;, Value =&amp;amp;gt; 90, RecordTransaction =&amp;amp;gt; 0);&lt;br /&gt;
&lt;br /&gt;
The zero in the [[RecordTransaction]] argument informs RT not to record the change as a new transaction.&lt;br /&gt;
&lt;br /&gt;
== How to change ticket custom field values ==&lt;br /&gt;
&lt;br /&gt;
Step 1, get the custom field (CF) object or ID. Don&#039;t use the hardcoded CF ID from the database. [why?] Step 2, get the CF object by ticket object by ticket object (I hope you remember how to get a ticket object) and CF name.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
      my $CFName = &#039;MyCustomField&#039;;&lt;br /&gt;
      my $CF = RT::CustomField-&amp;amp;gt;new( $RT::SystemUser );&lt;br /&gt;
      $CF-&amp;amp;gt;LoadByNameAndQueue( Name =&amp;amp;gt; $CFName, Queue =&amp;amp;gt; $Ticket-&amp;amp;gt;Queue );&lt;br /&gt;
      # RT has bug/feature until 3.0.10, you should load global CF yourself&lt;br /&gt;
      unless( $CF-&amp;amp;gt;id ) {&lt;br /&gt;
        # queue 0 is special case and is a synonym for global queue&lt;br /&gt;
        $CF-&amp;amp;gt;LoadByNameAndQueue( Name =&amp;amp;gt; $CFName, Queue =&amp;amp;gt; &#039;0&#039; );&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      unless( $CF-&amp;amp;gt;id ) {&lt;br /&gt;
        $RT::Logger-&amp;amp;gt;error( &amp;quot;No field $CFName in queue &amp;quot;. $Ticket-&amp;amp;gt;QueueObj-&amp;amp;gt;Name );&lt;br /&gt;
        return undef;&lt;br /&gt;
      }&lt;br /&gt;
      ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we could add value to ticket:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 my $Value = &#039;MyValue&#039;;&lt;br /&gt;
 $Ticket-&amp;amp;gt;AddCustomFieldValue( Field =&amp;amp;gt; $CF, Value =&amp;amp;gt; $Value );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 $Ticket-&amp;amp;gt;AddCustomFieldValue( Field =&amp;amp;gt; $CF, Value =&amp;amp;gt; $Value, RecordTransaction =&amp;amp;gt; 0 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
you also could use custom field id instead of object.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 $Ticket-&amp;amp;gt;AddCustomFieldValue( Field =&amp;amp;gt; NN , Value =&amp;amp;gt; $Value );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Step by step or &amp;quot;Tickets, transactions and attachments&amp;quot; ==&lt;br /&gt;
&lt;br /&gt;
Lets look what happens with RT from the beginning when a user clicks on create button in their browser. Web server gets request with queue id, ticket subject and body, owner and etc. RT fetches info from the request that is needed for Ticket record: its Queue id, Status, Subject, [[CurrentUser]](Creator), and then runs the next code:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
     # init empty instance of RT::Ticket class&lt;br /&gt;
     my $TicketObj = RT::Ticket-&amp;amp;gt;new( $session{&#039;CurrentUser&#039;} );&lt;br /&gt;
     &lt;br /&gt;
     # create new record&lt;br /&gt;
     # if you more familiar with SQL then it&#039;s INSERT&lt;br /&gt;
     # this call is inherited from SearchBuilder API&lt;br /&gt;
     my $id = $TicketObj-&amp;amp;gt;Create( %ARGS );&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ticket is created and it&#039;s time to record transaction into table. RT has all info for this: ticket&#039;s id that was recently created and transaction type - &#039;Create&#039;.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
     # this call creates new transaction record&lt;br /&gt;
     # this is very similar to situation with new ticket record&lt;br /&gt;
     my $TransactionObj = $Ticket-&amp;amp;gt;_RecordTransaction( %ARGS );&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Transactions in RT has an many-to-one mapping with ticket. One ticket =&amp;amp;gt; one or more transactions. You can get collection of transactions by calling Transactions method on a ticket object:&lt;br /&gt;
&lt;br /&gt;
 my $transactions = $TicketObj-&amp;amp;gt;Transactions;&lt;br /&gt;
&lt;br /&gt;
Each transaction belongs to only one ticket and you get ticket object with the following code:&lt;br /&gt;
&lt;br /&gt;
 my $ticket = $TransactionObj-&amp;amp;gt;TicketObj;&lt;br /&gt;
&lt;br /&gt;
As you can see RT still didn&#039;t use content that you wrote in the body. Content is an RT::Attachment object. You know how RT creates new record and know about Ticket-Transaction relation, the same relationship applies to Attachments and Transactions.&lt;br /&gt;
&lt;br /&gt;
== From &amp;quot;User Defined&amp;quot; to a module ==&lt;br /&gt;
&lt;br /&gt;
User defined actions you write in the web UI are handy and quick way to write an action. However, at some point you want to re-use your action, make it configurable, edit it in more suitable editor rather than text area, make it more complex and consist of additional methods. So it&#039;s time to move from &amp;quot;User Defined&amp;quot; action to your first module file.&lt;br /&gt;
&lt;br /&gt;
 use strict;&lt;br /&gt;
 use warnings;&lt;br /&gt;
 &lt;br /&gt;
 package RT::Action::MyAction;&lt;br /&gt;
 use base qw(RT::Action::Generic);&lt;br /&gt;
 &lt;br /&gt;
 sub Prepare {&lt;br /&gt;
   my $self = shift;&lt;br /&gt;
 &lt;br /&gt;
   ... here goes preparation code ...&lt;br /&gt;
 &lt;br /&gt;
   return 1;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 sub Commit {&lt;br /&gt;
   my $self = shift;&lt;br /&gt;
 &lt;br /&gt;
   ... here goes commit code ...&lt;br /&gt;
 &lt;br /&gt;
   return 1;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 1;&lt;br /&gt;
&lt;br /&gt;
That&#039;s it. Save it as [=lib/RT/Action/MyAction.pm](it is important that the file have the same name as the package (&amp;quot;MyAction&amp;quot; in the example)), fill in preparation and commit code then you can register your action in the DB. Use the following data file and [[AddDatabaseRecords]] instructions.&lt;br /&gt;
&lt;br /&gt;
 @ScripActions = (&lt;br /&gt;
   {&lt;br /&gt;
     Name        =&amp;amp;gt; &#039;My super duper action&#039;,&lt;br /&gt;
     Description =&amp;amp;gt; &#039;Super-puper action that does hell of a job&#039; ,&lt;br /&gt;
     ExecModule =&amp;amp;gt; &#039;MyAction&#039;,&lt;br /&gt;
     Argument   =&amp;amp;gt; &#039;some argument if needed&#039;&lt;br /&gt;
   },&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Now your action in the DB and you can pick it for a scrip through the Web UI instead of picking &amp;quot;User Defined&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
Other documentation on this wiki that may help&lt;br /&gt;
&lt;br /&gt;
[[GlobalObjects]], [[ObjectModel]]&lt;br /&gt;
&lt;br /&gt;
== Special thanks ==&lt;br /&gt;
&lt;br /&gt;
* [[TimWilson]], who was the main editor and reviewer&lt;/div&gt;</summary>
		<author><name>Medea61</name></author>
	</entry>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=TransactionBatchStage&amp;diff=26289</id>
		<title>TransactionBatchStage</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=TransactionBatchStage&amp;diff=26289"/>
		<updated>2016-07-19T17:09:48Z</updated>

		<summary type="html">&lt;p&gt;Medea61: /* How it works? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
[[ScripExecOrder]] article gives you overview and example about what &amp;quot;stages&amp;quot; is and what happens if scrip in batch stage instead of create stage.&lt;br /&gt;
&lt;br /&gt;
In two words: If [[Scrip]] in batch stage then it&#039;s applied only when all transactions of the user&#039;s request have been created.&lt;br /&gt;
&lt;br /&gt;
== When do you want to use batch stage ==&lt;br /&gt;
&lt;br /&gt;
* When people resolve tickets they can write a comment, in some setups it&#039;s cool to send a notification that the ticket is resolved to requestor and add the comment to the email. RT allows user to leave comment blank or RT as well could create a resolve transaction earlier than a transaction for the comment. In this situation batch stage can help you, you can find example of a template below.&lt;br /&gt;
* Another situation when you need batch stage is custom field updates. Consider some page with custom fields change boxes and fields for other manipulations and for example you want set field X on status change. RT sets status (create transaction) in create stage your scrip updates a CF, but then RT reverts this change as it starts [[CFs]] update action which checks if object has values in arguments of the request, the new value is not there then RT deletes it.&lt;br /&gt;
* Keep in mind that if your TransactionBatch scrip sends email, the email address of the people notified will &#039;&#039;&#039;not&#039;&#039;&#039; be visible while users are composing a reply.&lt;br /&gt;
&lt;br /&gt;
== How to enable it? ==&lt;br /&gt;
&lt;br /&gt;
Add to RT_SiteConfig.pm (only needed in RT versions less than 3.8.2 which defaultes this to on)&lt;br /&gt;
&lt;br /&gt;
 Set($UseTransactionBatch , 1);&lt;br /&gt;
&lt;br /&gt;
Then restart server to apply changes and now you can set stage for scrips you want to run in batch stage.&lt;br /&gt;
&lt;br /&gt;
== How it works? ==&lt;br /&gt;
&lt;br /&gt;
This is complex [[Template]] that adds &amp;quot;last&amp;quot; comment to email. Template works in both stages, but works better in batch stage cause adds only comment that was added within resolve action only.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     -------------------- Clever &#039;resolved&#039; template ----------------------&lt;br /&gt;
     Subject: Resolved: {$Ticket-&amp;amp;gt;Subject}&lt;br /&gt;
     &lt;br /&gt;
     According to our records, your request has been resolved. If you have any&lt;br /&gt;
     further questions or concerns, please respond to this message.&lt;br /&gt;
     &lt;br /&gt;
     &lt;br /&gt;
     {&lt;br /&gt;
             my $old_user = $Ticket-&amp;amp;gt;CurrentUser;&lt;br /&gt;
             $Ticket-&amp;amp;gt;CurrentUser( $RT::SystemUser );&lt;br /&gt;
             my $batch = $Ticket-&amp;amp;gt;TransactionBatch;&lt;br /&gt;
             my $comment;&lt;br /&gt;
             if( !$batch || !ref($batch) ) {&lt;br /&gt;
                     $RT::Logger-&amp;amp;gt;info(&amp;quot;TransactionBatch stage is disabled,&lt;br /&gt;
                                     fallback to last comment.&lt;br /&gt;
                                     Turn on TransactionBatch stages        for acurate results.&amp;quot;);&lt;br /&gt;
                     my $transactions = $Ticket-&amp;amp;gt;Transactions;&lt;br /&gt;
                     $transactions-&amp;amp;gt;Limit( FIELD =&amp;amp;gt; &#039;Type&#039;, VALUE =&amp;amp;gt; &#039;Comment&#039; );&lt;br /&gt;
                     $transactions-&amp;amp;gt;OrderByCols( { FIELD =&amp;amp;gt; &#039;Created&#039;,&lt;br /&gt;
                                                   ORDER =&amp;amp;gt; &#039;DESC&#039; },&lt;br /&gt;
                                                 { FIELD =&amp;amp;gt; &#039;id&#039;,&lt;br /&gt;
                                                   ORDER =&amp;amp;gt; &#039;DESC&#039; } );&lt;br /&gt;
                     $transactions-&amp;amp;gt;RowsPerPage(1);&lt;br /&gt;
                     $comment = $transactions-&amp;amp;gt;First;&lt;br /&gt;
             } else {&lt;br /&gt;
                     $comment = (grep { ($_-&amp;amp;gt;Type eq &#039;Comment&#039;)? 1: 0;} @$batch)[0];&lt;br /&gt;
             }&lt;br /&gt;
             $OUT = &amp;quot; &amp;quot;;&lt;br /&gt;
             if ( $comment ) {&lt;br /&gt;
                     # Since we&#039;re effectively turning this comment into&lt;br /&gt;
                     # correspondence, it is possible to use RT::Record to alter&lt;br /&gt;
                     # history a bit here.  This is normally really frowned upon,&lt;br /&gt;
                     # but without this, users may be confused that the reply they&lt;br /&gt;
                     # got by email isn&#039;t visible in the Web UI, because they don&#039;t&lt;br /&gt;
                     # have the ShowTicketComment right&lt;br /&gt;
                     RT::Record::_Set($comment, ( Field =&amp;amp;gt; &#039;Type&#039;, Value =&amp;amp;gt; &#039;Correspond&#039; ));&lt;br /&gt;
                     $OUT = &amp;quot;Resolution:\n&amp;quot;;&lt;br /&gt;
                     $OUT .= (&amp;quot;-&amp;quot;x76) .&amp;quot;\n&amp;quot;;&lt;br /&gt;
                     $OUT .= $comment-&amp;amp;gt;Content;&lt;br /&gt;
             }&lt;br /&gt;
             $Ticket-&amp;amp;gt;CurrentUser( $old_user );&lt;br /&gt;
     }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can set the stage on your scrip from the Applies To page in 4.2, or from the Scrip page in 4.0.  In 4.2 you can even choose to run scrips in TransactionBatch mode on a per-queue basis.&lt;br /&gt;
&lt;br /&gt;
See also the [http://bestpractical.com/docs/rt/latest/initialdata.html#Scrips Initialdata docs]&lt;/div&gt;</summary>
		<author><name>Medea61</name></author>
	</entry>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=SendEmailAction&amp;diff=26288</id>
		<title>SendEmailAction</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=SendEmailAction&amp;diff=26288"/>
		<updated>2016-07-19T17:08:33Z</updated>

		<summary type="html">&lt;p&gt;Medea61: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following is built into 3.8.X&lt;br /&gt;
&lt;br /&gt;
This action handles the case where you want to send an email to a certain person, but not require that person to be on the ticket. E.g. whenever a ticket is created, you want to send an email to a certain group of people, but not add that group to the ticket.&lt;br /&gt;
&lt;br /&gt;
This action does not require any Perl code, just a database edit. It uses code already in RT.&lt;br /&gt;
&lt;br /&gt;
Create the following file, named [[SendEmailAction]].install:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    # Used to install a scrip action.&lt;br /&gt;
    #&lt;br /&gt;
    # To install,&lt;br /&gt;
    # execute&lt;br /&gt;
    #     /path/to/rt3/sbin/rt-setup-database --action insert \&lt;br /&gt;
    #         --datafile /path/to/SendEmailAction.install&lt;br /&gt;
    #&lt;br /&gt;
    @ScripActions = (&lt;br /&gt;
        { Name        =&amp;amp;gt; &#039;Send Email&#039;,&lt;br /&gt;
          Description =&amp;amp;gt; &#039;Sends a message to those specified in the template&#039;,&lt;br /&gt;
          ExecModule  =&amp;amp;gt; &#039;SendEmail&#039;,&lt;br /&gt;
          Argument    =&amp;amp;gt; &#039;&#039; },&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the comments in the file indicate, you &amp;quot;install&amp;quot; this file using the &#039;&#039;&#039;rt-setup-database&#039;&#039;&#039; utility.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rt-setup-database --action insert --datafile SendEmailAction.install&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now when you create a scrip, you should have a new action available to you. To use it, first create a template which determines the content of the message you are sending, as well as the person or persons that will be getting this message.&lt;br /&gt;
&lt;br /&gt;
Here is an example of a template you could use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    To: user1@example.org, user2@example.org&lt;br /&gt;
    Bcc: user3@example.org&lt;br /&gt;
    Subject: {$Ticket-&amp;amp;gt;Subject}&lt;br /&gt;
    &lt;br /&gt;
    A ticket has been created in this queue.&lt;br /&gt;
    &lt;br /&gt;
    {$RT::WebURL}Ticket/Display.html?id={$Ticket-&amp;amp;gt;id}&lt;br /&gt;
    &lt;br /&gt;
    -------------&lt;br /&gt;
    &lt;br /&gt;
    {$Transaction-&amp;amp;gt;Content()}&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, create a scrip. Set the condition to &amp;quot;on create&amp;quot;, the action to &amp;quot;send email&amp;quot;, and specify your newly created template.&lt;br /&gt;
&lt;br /&gt;
If your scrip was queue-specific, you may also want to create a scrip handling tickets getting assigned to the queue.&lt;br /&gt;
&lt;br /&gt;
To use this action to send email to the members of an RT Group, use a template like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    To: { my $GroupObj = RT::Group-&amp;amp;gt;new($RT::SystemUser);&lt;br /&gt;
    $GroupObj-&amp;amp;gt;LoadUserDefinedGroup(&#039;Group Name&#039;);&lt;br /&gt;
    $GroupObj-&amp;amp;gt;MemberEmailAddressesAsString()}&lt;br /&gt;
    Subject: {$Ticket-&amp;amp;gt;Subject}&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    A ticket has been created in this queue.&lt;br /&gt;
    &lt;br /&gt;
    {$RT::WebURL}Ticket/Display.html?id={$Ticket-&amp;amp;gt;id}&lt;br /&gt;
    &lt;br /&gt;
    -------------&lt;br /&gt;
    &lt;br /&gt;
    {$Transaction-&amp;amp;gt;Content()}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Small problem with v3.8.4 and empty ticket body ==&lt;br /&gt;
&lt;br /&gt;
SendEmail fails with Request Tracker v3.8.4 if the body of the request is empty. For example if using the rt shell to create a ticket (useful for testing) like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rt create -t ticket set subject=&#039;TEST - please ignore&#039; queue=&#039;Testing&#039; requestor=&#039;address@thing.com&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then the ticket has no content and there is an error message (Ubuntu Karmic puts this is in /var/log/syslog) like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RT: error:    unexpected end of header (/usr/share/request-tracker3.8/lib/RT/Template_Overlay.pm:356)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Medea61</name></author>
	</entry>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=BounceMerge&amp;diff=26287</id>
		<title>BounceMerge</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=BounceMerge&amp;diff=26287"/>
		<updated>2016-07-19T17:04:41Z</updated>

		<summary type="html">&lt;p&gt;Medea61: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a scrip which checks if a newly generated ticket was created by a mail bounce.&lt;br /&gt;
&lt;br /&gt;
If yes, it tries to deduce the original ticket-id and merges this new ticket into the old one.&lt;br /&gt;
&lt;br /&gt;
The scrip logic is quite conservative, only if the same [[TicketID]] is found both in a quoted Message-ID and a RT-Ticket: header, then the scrip merges the tickets.&lt;br /&gt;
&lt;br /&gt;
Note that this requires an accurate Return-Path header. This should normally be added by the final MTA in the chain.&lt;br /&gt;
&lt;br /&gt;
Note also that this causes the logged creation message to be inaccurate, suggesting that the ticket being merged into has just been created.&lt;br /&gt;
&lt;br /&gt;
== Install ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Condition:&amp;lt;/u&amp;gt; On Create&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Template:&amp;lt;/u&amp;gt; Blank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Custom Condition:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 return 1;  # n/a&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Custom Action Preparation:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 return 1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Custom Action Cleanup Code:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    #&lt;br /&gt;
    # Merge mail bounce into old ticket.&lt;br /&gt;
    #&lt;br /&gt;
    # Otmar Lendl &amp;amp;lt;ol@bofh.priv.at&amp;amp;gt;  2009/07/24&lt;br /&gt;
    #&lt;br /&gt;
    my $ticket = $self-&amp;amp;gt;TicketObj;&lt;br /&gt;
    my $tr     = $self-&amp;amp;gt;TransactionObj;&lt;br /&gt;
    &lt;br /&gt;
    # possible sources of ticket-IDs:&lt;br /&gt;
    &lt;br /&gt;
    # Message-ID of the mail we sent:&lt;br /&gt;
    # example: Message-ID: &amp;amp;lt;rt-3.8.2-1611-1247727152-952.14150-6-0@CERT.at&amp;amp;gt;&lt;br /&gt;
    my $msgregex = &#039;&amp;amp;lt;rt-&#039;. $RT::VERSION .&#039;-\d+-\d+-\d+\.(\d+)-\d+-\d+@&#039;. RT-&amp;amp;gt;Config-&amp;amp;gt;Get(&#039;Organization&#039;) .&#039;&amp;amp;gt;&#039;;&lt;br /&gt;
    &lt;br /&gt;
    # RT-Ticket: header:&lt;br /&gt;
    # example: RT-Ticket: CERT.at #14150&lt;br /&gt;
    my $rttregex = &#039;^RT-Ticket: &#039; .  RT-&amp;amp;gt;Config-&amp;amp;gt;Get(&#039;rtname&#039;) .&#039; #(\d+)&#039;;&lt;br /&gt;
    &lt;br /&gt;
    my $Attachments = $tr-&amp;amp;gt;Attachments;&lt;br /&gt;
    # get first attachment&lt;br /&gt;
    my $a = $Attachments-&amp;amp;gt;Next;&lt;br /&gt;
    return(1) unless ($a);&lt;br /&gt;
    &lt;br /&gt;
    my $rp = $a-&amp;amp;gt;GetHeader(&#039;Return-Path&#039;);&lt;br /&gt;
    my $ct = $a-&amp;amp;gt;ContentType;&lt;br /&gt;
    &lt;br /&gt;
    # bounce?&lt;br /&gt;
    return(1) unless (($rp eq &#039;&amp;amp;lt;&amp;amp;gt;&#039;) or ($ct eq &#039;multipart/report&#039;));&lt;br /&gt;
    print STDERR &amp;quot;BounceMerge: Looks like a bounce ($rp/$ct). Trying to find ticket-ID.\n&amp;quot;;&lt;br /&gt;
    # .. which is potentially hidden in other attachments. Collect them all first.&lt;br /&gt;
    my $mail = &amp;quot;&amp;quot;;&lt;br /&gt;
    do {&lt;br /&gt;
     my $oh = $a-&amp;amp;gt;Headers;&lt;br /&gt;
     my $oc = $a-&amp;amp;gt;OriginalContent;&lt;br /&gt;
     $mail .= &amp;quot;\n----------------- &amp;quot; . $a-&amp;amp;gt;id . &amp;quot; ---------\n&amp;quot; . $oh if ($oh);&lt;br /&gt;
     $mail .= &amp;quot;\n----------------- &amp;quot; . $a-&amp;amp;gt;id . &amp;quot; ---------\n&amp;quot; . $oc if ($oc);&lt;br /&gt;
    } while ($a = $Attachments-&amp;amp;gt;Next);&lt;br /&gt;
    &lt;br /&gt;
    # look for a message-ID:&lt;br /&gt;
    &lt;br /&gt;
    my $id_msg = -1;&lt;br /&gt;
    my $id_hdr = -2;&lt;br /&gt;
    &lt;br /&gt;
    $id_msg = $1 if ($mail =~ /$msgregex/);&lt;br /&gt;
    $id_hdr = $1 if ($mail =~ /$rttregex/m);&lt;br /&gt;
    &lt;br /&gt;
    if (($id_hdr == $id_msg) and ($id_hdr != $ticket-&amp;amp;gt;EffectiveId) ) {&lt;br /&gt;
     print STDERR &amp;quot;BounceMerge: Removing requestors and merging into $id_msg\n&amp;quot;;&lt;br /&gt;
     my  @reqs = split(/[\s,]+/, $ticket-&amp;amp;gt;RequestorAddresses);&lt;br /&gt;
     foreach (@reqs) {&lt;br /&gt;
       $ticket-&amp;amp;gt;DeleteWatcher(&lt;br /&gt;
         Type    =&amp;amp;gt; &amp;quot;Requestor&amp;quot;,&lt;br /&gt;
         Email   =&amp;amp;gt; $_,&lt;br /&gt;
         Silent  =&amp;amp;gt; 1) ;&lt;br /&gt;
     }&lt;br /&gt;
     $ticket-&amp;amp;gt;MergeInto($id_msg);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return(1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It&#039;s worth bearing in mind that there are cases where the bounces may not go into the queue you intended. The branch https://github.com/jmdh/rt/tree/3.8%2Fignore_subject_ticket_for_queues may be of interest, if so.&lt;/div&gt;</summary>
		<author><name>Medea61</name></author>
	</entry>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=SpamFiltering&amp;diff=26286</id>
		<title>SpamFiltering</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=SpamFiltering&amp;diff=26286"/>
		<updated>2016-07-19T16:28:31Z</updated>

		<summary type="html">&lt;p&gt;Medea61: /* Collect spam/ham for training with procmail */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Spam Filtering =&lt;br /&gt;
&lt;br /&gt;
By moving all SPAM to a single queue, you can easily purge (shred) it periodically. You might also take the opportunity to purge any RT users who do not have a ticket associated with them.&lt;br /&gt;
&lt;br /&gt;
Please find documented below 6 setups for processing spam (1a-1c, 2a-2c). In general, you want to filter your messages at the MTA, before they get RT if you can.&lt;br /&gt;
&lt;br /&gt;
The list archives also contain a number of [http://www.gossamer-threads.com/lists/rt/users/87056?search_string=Spam filtering in RT;#87056 useful tips]&lt;br /&gt;
&lt;br /&gt;
== 0. Pre-filtering &amp;amp;amp; scoring messages ==&lt;br /&gt;
&lt;br /&gt;
There are a number of ways of doing so, such as procmail or [http://pthbb.org/manual/software/mailfilter mailfilter] which can do other somewhat-RT-specific pre-processing as well.&lt;br /&gt;
&lt;br /&gt;
== 1. Pre-filtered mail ==&lt;br /&gt;
&lt;br /&gt;
There are several options for processing messages once scored:&lt;br /&gt;
&lt;br /&gt;
=== a. Pre-filtered mail + ::Filter::SpamAssassin (=&amp;amp;gt; Spam Queue) ===&lt;br /&gt;
&lt;br /&gt;
http://codepad.org/HQmnr0AG based on&lt;br /&gt;
&lt;br /&gt;
http://documentroot.com/SpamAssassin.pm based on RT::Interface::Email::Filter::SpamAssassin from 3.8.1&lt;br /&gt;
&lt;br /&gt;
This updated version of the filter provides several options for handling potential spam, such as rejecting all messages above a certain score, and filing others in a SPAM queue.&lt;br /&gt;
&lt;br /&gt;
=== b. Pre-filtered mail + Scrip =&amp;amp;gt; Queue ===&lt;br /&gt;
&lt;br /&gt;
In the example below a score of 5 or more is needed. Edit preparation code if you want to modify the level.&lt;br /&gt;
&lt;br /&gt;
Create new Scrip using following information:&lt;br /&gt;
&lt;br /&gt;
*Condition: On Create &lt;br /&gt;
*Action: User Defined &lt;br /&gt;
*Custom action preparation code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 # Match ***** level spam. You might want to set this higher/lower if needed&lt;br /&gt;
 my $match = &#039;\*\*\*\*\*&#039;;&lt;br /&gt;
 my $inMessage = $self-&amp;amp;gt;TransactionObj-&amp;amp;gt;Attachments-&amp;amp;gt;First;&lt;br /&gt;
 return 0 if (!$inMessage);  # if no message attachment - assume web UI&lt;br /&gt;
 return 0 if (!$inMessage-&amp;amp;gt;GetHeader(&#039;Received&#039;));  # exit if not email message&lt;br /&gt;
 &lt;br /&gt;
 my $spamLevel = $inMessage-&amp;amp;gt;GetHeader(&#039;X-Spam-Level&#039;);&lt;br /&gt;
 return ( $spamLevel !~ /$match/i ) ? 0 : 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Custom action cleanup code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 my $newqueue = &#039;spam&#039;;&lt;br /&gt;
 my ($status, $msg) = $self-&amp;amp;gt;TicketObj-&amp;amp;gt;SetQueue($newqueue);&lt;br /&gt;
 return $status ? undef : 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== c. Pre-filtered mail + ProcMail =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
A procmail recipe (for each queue/(correspond|comment) pair) can be used to send spam to a spam queue in RT. Note that:&lt;br /&gt;
&lt;br /&gt;
* the flags bh need to be set so rt-mailgate sees both the body and header of the message.&lt;br /&gt;
* the absence of a second colon so there is no lockfile&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;pre&amp;gt;&lt;br /&gt;
 PATH=/usr/local/bin:/bin/:/usr/bin&lt;br /&gt;
 LOGFILE=/var/log/procmail.log&lt;br /&gt;
 #rt-mailgate has already saved the message in the rt database&lt;br /&gt;
 #set DEFAULT to be somewhere real if you want procmail to save the message elsewhere&lt;br /&gt;
 DEFAULT=/dev/null&lt;br /&gt;
 &lt;br /&gt;
  #Messages &amp;amp;gt;300000 characters proceed to recipient (unlikely to be spam)&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 * &amp;amp;gt; 300000&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue default --action correspond --url http://localhost/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is fired send to spam queue&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 * ^X-Spam-Level: \*\*\*\*\*&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue spam --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is not fired then send to expected destination&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue default --action correspond --url http://localhost/rt/&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Unfiltered messages ===&lt;br /&gt;
&lt;br /&gt;
=== a. Unfiltered mail + ::Filter::SpamAssassin (=&amp;amp;gt; Spam Queue) ===&lt;br /&gt;
&lt;br /&gt;
RT::Interface::Email::Filter::SpamAssassin above (1a) can also pass unscored messages off to SpamAssassin for processing.&lt;br /&gt;
&lt;br /&gt;
=== b. Unfiltered mail + ProcMail &amp;amp;amp; SpamAssassin =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
This procmail recipe is similar to 1c. above, except that it handles previously unscored messages, and accepts many of the rt-mailgate parameters as environment variables so that it may be easily used with multiple aliases.&lt;br /&gt;
&lt;br /&gt;
Aliases:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 rt: &amp;quot;|/usr/local/bin/procmail -m ACTION=correspond QUEUE=General /usr/local/etc/procmail/rt-deliver.rc&amp;quot;&lt;br /&gt;
 rt-comment: &amp;quot;|/usr/local/bin/procmail -m ACTION=comment QUEUE=General /usr/local/etc/procmail/rt-deliver.rc&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/usr/local/etc/procmail/rt-deliver.rc:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #Messages &amp;amp;gt;300000 characters proceed to recipient (unlikely to be spam)&lt;br /&gt;
 :0w&lt;br /&gt;
 * &amp;amp;gt; 300000&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue $QUEUE --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #Is it spam?&lt;br /&gt;
 :0fw: spamassassin.lock&lt;br /&gt;
 * &amp;amp;lt; 300000&lt;br /&gt;
 | /usr/local/bin/spamc&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is fired send to spam queue&lt;br /&gt;
 :0w&lt;br /&gt;
 * ^X-Spam-Status: Yes&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue Spam --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is not fired then send to expected destination&lt;br /&gt;
 :0w&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue $QUEUE --action $ACTION --url http://localhost/rt/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== c. ProcMail + SpamAssassin + Scrip =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
http://www.soundwave.net/~wmono/rt/&lt;br /&gt;
&lt;br /&gt;
== 3. Mis-handled messages ==&lt;br /&gt;
&lt;br /&gt;
=== a. False positives: Greylist ===&lt;br /&gt;
&lt;br /&gt;
2c above outlines a general (non-procmail specific) setup (steps 1 through 6 for RT) to automatically greylist suspect messages. Legitimate requestors may reply to an autoresponse and have their misfiled message requeued.&lt;br /&gt;
&lt;br /&gt;
=== b. False negatives: QuickSpamhandler ===&lt;br /&gt;
&lt;br /&gt;
Note: [[QuickSpamHandler]] seems to no longer be available. The [http://search.cpan.org/~ruz/RT-Extension-ReportSpam-0.02/lib/RT/Extension/ReportSpam.pm RT::Extension::ReportSpam] is fairly similar though.&lt;br /&gt;
&lt;br /&gt;
This extension provides a few tools that can be used for manual triage of SPAM in low-traffic installation, or handling the odd message that leaks through your automated filters:&lt;br /&gt;
&lt;br /&gt;
* Adds alternate forms of the &amp;quot;Unowned Tickets&amp;quot; and &amp;quot;My Tickets&amp;quot; global searches, which exclude messages in the spam queue.&lt;br /&gt;
* Adds a link to the &amp;quot;Search - Unowned Tickets&amp;quot; query which permits you to instantly vanquish a ticket if the subject is sufficient to convince you the message is SPAM.&lt;br /&gt;
* Adds a link to the Ticket tool bar that will instantly vanquish the displayed ticket.&lt;br /&gt;
&lt;br /&gt;
Vanquished tickets are moved to a designated SPAM queue; the default is named &amp;quot;Possible SPAM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Installation ====&lt;br /&gt;
&lt;br /&gt;
* Download the [http://zephyrgeek.qatar.cmu.edu/RT/QuickSpamHandler.tgz archive]&lt;br /&gt;
* Unpack it&lt;br /&gt;
* ./configure&lt;br /&gt;
* make install&lt;br /&gt;
* Read and act on the output from the previous command.&lt;br /&gt;
&lt;br /&gt;
Really, the only tricky bit is the database update. If I ever figure out a better way to do this I&#039;ll make sure to update the archive. Hopefully someone will find this useful. If you do, please drop me a line!&lt;br /&gt;
&lt;br /&gt;
=== c. False negatives: Bookmarklet ===&lt;br /&gt;
&lt;br /&gt;
An alternative to QuickSpamHandler above, this bookmarklet moves the displayed ticket to the spam queue (change 12 to the appropriate ID for your queue), and sets the status to rejected.&lt;br /&gt;
&lt;br /&gt;
 javascript:self.location=self.location+&#039;&amp;amp;amp;Status=resolved&amp;amp;amp;Queue=12&#039;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Thus you can distinguish messages which you have already decided are spam, from those which are automatically filed into that queue.&lt;br /&gt;
&lt;br /&gt;
== Collect spam/ham for training with procmail ==&lt;br /&gt;
&lt;br /&gt;
In /etc/postfix, I am maintaining a file named rt-aliases. It contains, for every queue:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 rt:         &amp;quot;|/usr/bin/procmail -m /etc/procmailrcs/general&amp;quot;&lt;br /&gt;
 rt-comment: &amp;quot;|/usr/bin/procmail -m /etc/procmailrcs/general-comment&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in /etc/procmailrcs, the file &amp;quot;general&amp;quot; looks like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 PATH=/usr/local/bin:/bin:/usr/bin&lt;br /&gt;
 LOGFILE=/var/log/procmail.log&lt;br /&gt;
 INCLUDERC=/etc/procmailrcs/_spamfilter&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;_spamfilter&amp;quot; include does the actual collection:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 # The lock file ensures that only 1 spamassassin invocation happens&lt;br /&gt;
 # at 1 time, to keep the load down.&lt;br /&gt;
 #&lt;br /&gt;
 :0fw: spamassassin.lock&lt;br /&gt;
 * &amp;amp;lt; 256000&lt;br /&gt;
 | /usr/bin/spamassassin&lt;br /&gt;
 &lt;br /&gt;
 # Mails with a score of 15 or higher are almost certainly spam (with 0.05%&lt;br /&gt;
 # false positives according to rules/STATISTICS.txt). Let&#039;s put them in a&lt;br /&gt;
 # different mbox. (This one is optional.)&lt;br /&gt;
 :0:&lt;br /&gt;
 * ^X-Spam-Level: \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*&lt;br /&gt;
 /local/mailcopy/almost-certainly-spam&lt;br /&gt;
 &lt;br /&gt;
 # Work around procmail bug: any output on stderr will cause the &amp;quot;F&amp;quot; in &amp;quot;From&amp;quot;&lt;br /&gt;
 # to be dropped.  This will re-add it.&lt;br /&gt;
 :0&lt;br /&gt;
 * ^^rom[ ]&lt;br /&gt;
 {&lt;br /&gt;
    LOG=&amp;quot;*** Dropped F off From_ header! Fixing up. &amp;quot;&lt;br /&gt;
 &lt;br /&gt;
   :0 fhw&lt;br /&gt;
   | sed -e &#039;1s/^/F/&#039;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 :0 c&lt;br /&gt;
 /local/mailcopy/unconfirmed-ham&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Notes &amp;amp;amp; Other Resources ==&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to run `newaliases` (or equivalent) after you alter your configuration if appropriate.&lt;br /&gt;
&lt;br /&gt;
* [[SpamScore2Priority]]&lt;br /&gt;
* [http://pm-doc.sourceforge.net/pm-tips-body.html#procmail_flags Procmail flags documentation].&lt;/div&gt;</summary>
		<author><name>Medea61</name></author>
	</entry>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=SpamFiltering&amp;diff=26285</id>
		<title>SpamFiltering</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=SpamFiltering&amp;diff=26285"/>
		<updated>2016-07-19T16:27:43Z</updated>

		<summary type="html">&lt;p&gt;Medea61: /* b. Unfiltered mail + ProcMail &amp;amp;amp; SpamAssassin =&amp;amp;gt; Spam Queue */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Spam Filtering =&lt;br /&gt;
&lt;br /&gt;
By moving all SPAM to a single queue, you can easily purge (shred) it periodically. You might also take the opportunity to purge any RT users who do not have a ticket associated with them.&lt;br /&gt;
&lt;br /&gt;
Please find documented below 6 setups for processing spam (1a-1c, 2a-2c). In general, you want to filter your messages at the MTA, before they get RT if you can.&lt;br /&gt;
&lt;br /&gt;
The list archives also contain a number of [http://www.gossamer-threads.com/lists/rt/users/87056?search_string=Spam filtering in RT;#87056 useful tips]&lt;br /&gt;
&lt;br /&gt;
== 0. Pre-filtering &amp;amp;amp; scoring messages ==&lt;br /&gt;
&lt;br /&gt;
There are a number of ways of doing so, such as procmail or [http://pthbb.org/manual/software/mailfilter mailfilter] which can do other somewhat-RT-specific pre-processing as well.&lt;br /&gt;
&lt;br /&gt;
== 1. Pre-filtered mail ==&lt;br /&gt;
&lt;br /&gt;
There are several options for processing messages once scored:&lt;br /&gt;
&lt;br /&gt;
=== a. Pre-filtered mail + ::Filter::SpamAssassin (=&amp;amp;gt; Spam Queue) ===&lt;br /&gt;
&lt;br /&gt;
http://codepad.org/HQmnr0AG based on&lt;br /&gt;
&lt;br /&gt;
http://documentroot.com/SpamAssassin.pm based on RT::Interface::Email::Filter::SpamAssassin from 3.8.1&lt;br /&gt;
&lt;br /&gt;
This updated version of the filter provides several options for handling potential spam, such as rejecting all messages above a certain score, and filing others in a SPAM queue.&lt;br /&gt;
&lt;br /&gt;
=== b. Pre-filtered mail + Scrip =&amp;amp;gt; Queue ===&lt;br /&gt;
&lt;br /&gt;
In the example below a score of 5 or more is needed. Edit preparation code if you want to modify the level.&lt;br /&gt;
&lt;br /&gt;
Create new Scrip using following information:&lt;br /&gt;
&lt;br /&gt;
*Condition: On Create &lt;br /&gt;
*Action: User Defined &lt;br /&gt;
*Custom action preparation code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 # Match ***** level spam. You might want to set this higher/lower if needed&lt;br /&gt;
 my $match = &#039;\*\*\*\*\*&#039;;&lt;br /&gt;
 my $inMessage = $self-&amp;amp;gt;TransactionObj-&amp;amp;gt;Attachments-&amp;amp;gt;First;&lt;br /&gt;
 return 0 if (!$inMessage);  # if no message attachment - assume web UI&lt;br /&gt;
 return 0 if (!$inMessage-&amp;amp;gt;GetHeader(&#039;Received&#039;));  # exit if not email message&lt;br /&gt;
 &lt;br /&gt;
 my $spamLevel = $inMessage-&amp;amp;gt;GetHeader(&#039;X-Spam-Level&#039;);&lt;br /&gt;
 return ( $spamLevel !~ /$match/i ) ? 0 : 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Custom action cleanup code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 my $newqueue = &#039;spam&#039;;&lt;br /&gt;
 my ($status, $msg) = $self-&amp;amp;gt;TicketObj-&amp;amp;gt;SetQueue($newqueue);&lt;br /&gt;
 return $status ? undef : 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== c. Pre-filtered mail + ProcMail =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
A procmail recipe (for each queue/(correspond|comment) pair) can be used to send spam to a spam queue in RT. Note that:&lt;br /&gt;
&lt;br /&gt;
* the flags bh need to be set so rt-mailgate sees both the body and header of the message.&lt;br /&gt;
* the absence of a second colon so there is no lockfile&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;pre&amp;gt;&lt;br /&gt;
 PATH=/usr/local/bin:/bin/:/usr/bin&lt;br /&gt;
 LOGFILE=/var/log/procmail.log&lt;br /&gt;
 #rt-mailgate has already saved the message in the rt database&lt;br /&gt;
 #set DEFAULT to be somewhere real if you want procmail to save the message elsewhere&lt;br /&gt;
 DEFAULT=/dev/null&lt;br /&gt;
 &lt;br /&gt;
  #Messages &amp;amp;gt;300000 characters proceed to recipient (unlikely to be spam)&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 * &amp;amp;gt; 300000&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue default --action correspond --url http://localhost/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is fired send to spam queue&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 * ^X-Spam-Level: \*\*\*\*\*&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue spam --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is not fired then send to expected destination&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue default --action correspond --url http://localhost/rt/&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Unfiltered messages ===&lt;br /&gt;
&lt;br /&gt;
=== a. Unfiltered mail + ::Filter::SpamAssassin (=&amp;amp;gt; Spam Queue) ===&lt;br /&gt;
&lt;br /&gt;
RT::Interface::Email::Filter::SpamAssassin above (1a) can also pass unscored messages off to SpamAssassin for processing.&lt;br /&gt;
&lt;br /&gt;
=== b. Unfiltered mail + ProcMail &amp;amp;amp; SpamAssassin =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
This procmail recipe is similar to 1c. above, except that it handles previously unscored messages, and accepts many of the rt-mailgate parameters as environment variables so that it may be easily used with multiple aliases.&lt;br /&gt;
&lt;br /&gt;
Aliases:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 rt: &amp;quot;|/usr/local/bin/procmail -m ACTION=correspond QUEUE=General /usr/local/etc/procmail/rt-deliver.rc&amp;quot;&lt;br /&gt;
 rt-comment: &amp;quot;|/usr/local/bin/procmail -m ACTION=comment QUEUE=General /usr/local/etc/procmail/rt-deliver.rc&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/usr/local/etc/procmail/rt-deliver.rc:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #Messages &amp;amp;gt;300000 characters proceed to recipient (unlikely to be spam)&lt;br /&gt;
 :0w&lt;br /&gt;
 * &amp;amp;gt; 300000&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue $QUEUE --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #Is it spam?&lt;br /&gt;
 :0fw: spamassassin.lock&lt;br /&gt;
 * &amp;amp;lt; 300000&lt;br /&gt;
 | /usr/local/bin/spamc&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is fired send to spam queue&lt;br /&gt;
 :0w&lt;br /&gt;
 * ^X-Spam-Status: Yes&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue Spam --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is not fired then send to expected destination&lt;br /&gt;
 :0w&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue $QUEUE --action $ACTION --url http://localhost/rt/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== c. ProcMail + SpamAssassin + Scrip =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
http://www.soundwave.net/~wmono/rt/&lt;br /&gt;
&lt;br /&gt;
== 3. Mis-handled messages ==&lt;br /&gt;
&lt;br /&gt;
=== a. False positives: Greylist ===&lt;br /&gt;
&lt;br /&gt;
2c above outlines a general (non-procmail specific) setup (steps 1 through 6 for RT) to automatically greylist suspect messages. Legitimate requestors may reply to an autoresponse and have their misfiled message requeued.&lt;br /&gt;
&lt;br /&gt;
=== b. False negatives: QuickSpamhandler ===&lt;br /&gt;
&lt;br /&gt;
Note: [[QuickSpamHandler]] seems to no longer be available. The [http://search.cpan.org/~ruz/RT-Extension-ReportSpam-0.02/lib/RT/Extension/ReportSpam.pm RT::Extension::ReportSpam] is fairly similar though.&lt;br /&gt;
&lt;br /&gt;
This extension provides a few tools that can be used for manual triage of SPAM in low-traffic installation, or handling the odd message that leaks through your automated filters:&lt;br /&gt;
&lt;br /&gt;
* Adds alternate forms of the &amp;quot;Unowned Tickets&amp;quot; and &amp;quot;My Tickets&amp;quot; global searches, which exclude messages in the spam queue.&lt;br /&gt;
* Adds a link to the &amp;quot;Search - Unowned Tickets&amp;quot; query which permits you to instantly vanquish a ticket if the subject is sufficient to convince you the message is SPAM.&lt;br /&gt;
* Adds a link to the Ticket tool bar that will instantly vanquish the displayed ticket.&lt;br /&gt;
&lt;br /&gt;
Vanquished tickets are moved to a designated SPAM queue; the default is named &amp;quot;Possible SPAM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Installation ====&lt;br /&gt;
&lt;br /&gt;
* Download the [http://zephyrgeek.qatar.cmu.edu/RT/QuickSpamHandler.tgz archive]&lt;br /&gt;
* Unpack it&lt;br /&gt;
* ./configure&lt;br /&gt;
* make install&lt;br /&gt;
* Read and act on the output from the previous command.&lt;br /&gt;
&lt;br /&gt;
Really, the only tricky bit is the database update. If I ever figure out a better way to do this I&#039;ll make sure to update the archive. Hopefully someone will find this useful. If you do, please drop me a line!&lt;br /&gt;
&lt;br /&gt;
=== c. False negatives: Bookmarklet ===&lt;br /&gt;
&lt;br /&gt;
An alternative to QuickSpamHandler above, this bookmarklet moves the displayed ticket to the spam queue (change 12 to the appropriate ID for your queue), and sets the status to rejected.&lt;br /&gt;
&lt;br /&gt;
 javascript:self.location=self.location+&#039;&amp;amp;amp;Status=resolved&amp;amp;amp;Queue=12&#039;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Thus you can distinguish messages which you have already decided are spam, from those which are automatically filed into that queue.&lt;br /&gt;
&lt;br /&gt;
== Collect spam/ham for training with procmail ==&lt;br /&gt;
&lt;br /&gt;
In /etc/postfix, I am maintaining a file named rt-aliases. It contains, for every queue:&lt;br /&gt;
&lt;br /&gt;
 rt:         &amp;quot;|/usr/bin/procmail -m /etc/procmailrcs/general&amp;quot;&lt;br /&gt;
 rt-comment: &amp;quot;|/usr/bin/procmail -m /etc/procmailrcs/general-comment&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
in /etc/procmailrcs, the file &amp;quot;general&amp;quot; looks like:&lt;br /&gt;
&lt;br /&gt;
 PATH=/usr/local/bin:/bin:/usr/bin&lt;br /&gt;
 LOGFILE=/var/log/procmail.log&lt;br /&gt;
 INCLUDERC=/etc/procmailrcs/_spamfilter&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
The &amp;quot;_spamfilter&amp;quot; include does the actual collection:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# The lock file ensures that only 1 spamassassin invocation happens&lt;br /&gt;
 # at 1 time, to keep the load down.&lt;br /&gt;
 #&lt;br /&gt;
 :0fw: spamassassin.lock&lt;br /&gt;
 * &amp;amp;lt; 256000&lt;br /&gt;
 | /usr/bin/spamassassin&lt;br /&gt;
 &lt;br /&gt;
 # Mails with a score of 15 or higher are almost certainly spam (with 0.05%&lt;br /&gt;
 # false positives according to rules/STATISTICS.txt). Let&#039;s put them in a&lt;br /&gt;
 # different mbox. (This one is optional.)&lt;br /&gt;
 :0:&lt;br /&gt;
 * ^X-Spam-Level: \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*&lt;br /&gt;
 /local/mailcopy/almost-certainly-spam&lt;br /&gt;
 &lt;br /&gt;
 # Work around procmail bug: any output on stderr will cause the &amp;quot;F&amp;quot; in &amp;quot;From&amp;quot;&lt;br /&gt;
 # to be dropped.  This will re-add it.&lt;br /&gt;
 :0&lt;br /&gt;
 * ^^rom[ ]&lt;br /&gt;
 {&lt;br /&gt;
    LOG=&amp;quot;*** Dropped F off From_ header! Fixing up. &amp;quot;&lt;br /&gt;
 &lt;br /&gt;
   :0 fhw&lt;br /&gt;
   | sed -e &#039;1s/^/F/&#039;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 :0 c&lt;br /&gt;
 /local/mailcopy/unconfirmed-ham&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Notes &amp;amp;amp; Other Resources ==&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to run `newaliases` (or equivalent) after you alter your configuration if appropriate.&lt;br /&gt;
&lt;br /&gt;
* [[SpamScore2Priority]]&lt;br /&gt;
* [http://pm-doc.sourceforge.net/pm-tips-body.html#procmail_flags Procmail flags documentation].&lt;/div&gt;</summary>
		<author><name>Medea61</name></author>
	</entry>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=SpamFiltering&amp;diff=26284</id>
		<title>SpamFiltering</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=SpamFiltering&amp;diff=26284"/>
		<updated>2016-07-19T16:26:55Z</updated>

		<summary type="html">&lt;p&gt;Medea61: /* c. Pre-filtered mail + ProcMail =&amp;amp;gt; Spam Queue */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Spam Filtering =&lt;br /&gt;
&lt;br /&gt;
By moving all SPAM to a single queue, you can easily purge (shred) it periodically. You might also take the opportunity to purge any RT users who do not have a ticket associated with them.&lt;br /&gt;
&lt;br /&gt;
Please find documented below 6 setups for processing spam (1a-1c, 2a-2c). In general, you want to filter your messages at the MTA, before they get RT if you can.&lt;br /&gt;
&lt;br /&gt;
The list archives also contain a number of [http://www.gossamer-threads.com/lists/rt/users/87056?search_string=Spam filtering in RT;#87056 useful tips]&lt;br /&gt;
&lt;br /&gt;
== 0. Pre-filtering &amp;amp;amp; scoring messages ==&lt;br /&gt;
&lt;br /&gt;
There are a number of ways of doing so, such as procmail or [http://pthbb.org/manual/software/mailfilter mailfilter] which can do other somewhat-RT-specific pre-processing as well.&lt;br /&gt;
&lt;br /&gt;
== 1. Pre-filtered mail ==&lt;br /&gt;
&lt;br /&gt;
There are several options for processing messages once scored:&lt;br /&gt;
&lt;br /&gt;
=== a. Pre-filtered mail + ::Filter::SpamAssassin (=&amp;amp;gt; Spam Queue) ===&lt;br /&gt;
&lt;br /&gt;
http://codepad.org/HQmnr0AG based on&lt;br /&gt;
&lt;br /&gt;
http://documentroot.com/SpamAssassin.pm based on RT::Interface::Email::Filter::SpamAssassin from 3.8.1&lt;br /&gt;
&lt;br /&gt;
This updated version of the filter provides several options for handling potential spam, such as rejecting all messages above a certain score, and filing others in a SPAM queue.&lt;br /&gt;
&lt;br /&gt;
=== b. Pre-filtered mail + Scrip =&amp;amp;gt; Queue ===&lt;br /&gt;
&lt;br /&gt;
In the example below a score of 5 or more is needed. Edit preparation code if you want to modify the level.&lt;br /&gt;
&lt;br /&gt;
Create new Scrip using following information:&lt;br /&gt;
&lt;br /&gt;
*Condition: On Create &lt;br /&gt;
*Action: User Defined &lt;br /&gt;
*Custom action preparation code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 # Match ***** level spam. You might want to set this higher/lower if needed&lt;br /&gt;
 my $match = &#039;\*\*\*\*\*&#039;;&lt;br /&gt;
 my $inMessage = $self-&amp;amp;gt;TransactionObj-&amp;amp;gt;Attachments-&amp;amp;gt;First;&lt;br /&gt;
 return 0 if (!$inMessage);  # if no message attachment - assume web UI&lt;br /&gt;
 return 0 if (!$inMessage-&amp;amp;gt;GetHeader(&#039;Received&#039;));  # exit if not email message&lt;br /&gt;
 &lt;br /&gt;
 my $spamLevel = $inMessage-&amp;amp;gt;GetHeader(&#039;X-Spam-Level&#039;);&lt;br /&gt;
 return ( $spamLevel !~ /$match/i ) ? 0 : 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Custom action cleanup code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 my $newqueue = &#039;spam&#039;;&lt;br /&gt;
 my ($status, $msg) = $self-&amp;amp;gt;TicketObj-&amp;amp;gt;SetQueue($newqueue);&lt;br /&gt;
 return $status ? undef : 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== c. Pre-filtered mail + ProcMail =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
A procmail recipe (for each queue/(correspond|comment) pair) can be used to send spam to a spam queue in RT. Note that:&lt;br /&gt;
&lt;br /&gt;
* the flags bh need to be set so rt-mailgate sees both the body and header of the message.&lt;br /&gt;
* the absence of a second colon so there is no lockfile&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;pre&amp;gt;&lt;br /&gt;
 PATH=/usr/local/bin:/bin/:/usr/bin&lt;br /&gt;
 LOGFILE=/var/log/procmail.log&lt;br /&gt;
 #rt-mailgate has already saved the message in the rt database&lt;br /&gt;
 #set DEFAULT to be somewhere real if you want procmail to save the message elsewhere&lt;br /&gt;
 DEFAULT=/dev/null&lt;br /&gt;
 &lt;br /&gt;
  #Messages &amp;amp;gt;300000 characters proceed to recipient (unlikely to be spam)&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 * &amp;amp;gt; 300000&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue default --action correspond --url http://localhost/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is fired send to spam queue&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 * ^X-Spam-Level: \*\*\*\*\*&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue spam --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is not fired then send to expected destination&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue default --action correspond --url http://localhost/rt/&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Unfiltered messages ===&lt;br /&gt;
&lt;br /&gt;
=== a. Unfiltered mail + ::Filter::SpamAssassin (=&amp;amp;gt; Spam Queue) ===&lt;br /&gt;
&lt;br /&gt;
RT::Interface::Email::Filter::SpamAssassin above (1a) can also pass unscored messages off to SpamAssassin for processing.&lt;br /&gt;
&lt;br /&gt;
=== b. Unfiltered mail + ProcMail &amp;amp;amp; SpamAssassin =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
This procmail recipe is similar to 1c. above, except that it handles previously unscored messages, and accepts many of the rt-mailgate parameters as environment variables so that it may be easily used with multiple aliases.&lt;br /&gt;
&lt;br /&gt;
Aliases:&lt;br /&gt;
&lt;br /&gt;
 rt: &amp;quot;|/usr/local/bin/procmail -m ACTION=correspond QUEUE=General /usr/local/etc/procmail/rt-deliver.rc&amp;quot;&lt;br /&gt;
 rt-comment: &amp;quot;|/usr/local/bin/procmail -m ACTION=comment QUEUE=General /usr/local/etc/procmail/rt-deliver.rc&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
/usr/local/etc/procmail/rt-deliver.rc:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#Messages &amp;amp;gt;300000 characters proceed to recipient (unlikely to be spam)&lt;br /&gt;
 :0w&lt;br /&gt;
 * &amp;amp;gt; 300000&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue $QUEUE --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #Is it spam?&lt;br /&gt;
 :0fw: spamassassin.lock&lt;br /&gt;
 * &amp;amp;lt; 300000&lt;br /&gt;
 | /usr/local/bin/spamc&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is fired send to spam queue&lt;br /&gt;
 :0w&lt;br /&gt;
 * ^X-Spam-Status: Yes&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue Spam --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is not fired then send to expected destination&lt;br /&gt;
 :0w&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue $QUEUE --action $ACTION --url http://localhost/rt/&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== c. ProcMail + SpamAssassin + Scrip =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
http://www.soundwave.net/~wmono/rt/&lt;br /&gt;
&lt;br /&gt;
== 3. Mis-handled messages ==&lt;br /&gt;
&lt;br /&gt;
=== a. False positives: Greylist ===&lt;br /&gt;
&lt;br /&gt;
2c above outlines a general (non-procmail specific) setup (steps 1 through 6 for RT) to automatically greylist suspect messages. Legitimate requestors may reply to an autoresponse and have their misfiled message requeued.&lt;br /&gt;
&lt;br /&gt;
=== b. False negatives: QuickSpamhandler ===&lt;br /&gt;
&lt;br /&gt;
Note: [[QuickSpamHandler]] seems to no longer be available. The [http://search.cpan.org/~ruz/RT-Extension-ReportSpam-0.02/lib/RT/Extension/ReportSpam.pm RT::Extension::ReportSpam] is fairly similar though.&lt;br /&gt;
&lt;br /&gt;
This extension provides a few tools that can be used for manual triage of SPAM in low-traffic installation, or handling the odd message that leaks through your automated filters:&lt;br /&gt;
&lt;br /&gt;
* Adds alternate forms of the &amp;quot;Unowned Tickets&amp;quot; and &amp;quot;My Tickets&amp;quot; global searches, which exclude messages in the spam queue.&lt;br /&gt;
* Adds a link to the &amp;quot;Search - Unowned Tickets&amp;quot; query which permits you to instantly vanquish a ticket if the subject is sufficient to convince you the message is SPAM.&lt;br /&gt;
* Adds a link to the Ticket tool bar that will instantly vanquish the displayed ticket.&lt;br /&gt;
&lt;br /&gt;
Vanquished tickets are moved to a designated SPAM queue; the default is named &amp;quot;Possible SPAM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Installation ====&lt;br /&gt;
&lt;br /&gt;
* Download the [http://zephyrgeek.qatar.cmu.edu/RT/QuickSpamHandler.tgz archive]&lt;br /&gt;
* Unpack it&lt;br /&gt;
* ./configure&lt;br /&gt;
* make install&lt;br /&gt;
* Read and act on the output from the previous command.&lt;br /&gt;
&lt;br /&gt;
Really, the only tricky bit is the database update. If I ever figure out a better way to do this I&#039;ll make sure to update the archive. Hopefully someone will find this useful. If you do, please drop me a line!&lt;br /&gt;
&lt;br /&gt;
=== c. False negatives: Bookmarklet ===&lt;br /&gt;
&lt;br /&gt;
An alternative to QuickSpamHandler above, this bookmarklet moves the displayed ticket to the spam queue (change 12 to the appropriate ID for your queue), and sets the status to rejected.&lt;br /&gt;
&lt;br /&gt;
 javascript:self.location=self.location+&#039;&amp;amp;amp;Status=resolved&amp;amp;amp;Queue=12&#039;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Thus you can distinguish messages which you have already decided are spam, from those which are automatically filed into that queue.&lt;br /&gt;
&lt;br /&gt;
== Collect spam/ham for training with procmail ==&lt;br /&gt;
&lt;br /&gt;
In /etc/postfix, I am maintaining a file named rt-aliases. It contains, for every queue:&lt;br /&gt;
&lt;br /&gt;
 rt:         &amp;quot;|/usr/bin/procmail -m /etc/procmailrcs/general&amp;quot;&lt;br /&gt;
 rt-comment: &amp;quot;|/usr/bin/procmail -m /etc/procmailrcs/general-comment&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
in /etc/procmailrcs, the file &amp;quot;general&amp;quot; looks like:&lt;br /&gt;
&lt;br /&gt;
 PATH=/usr/local/bin:/bin:/usr/bin&lt;br /&gt;
 LOGFILE=/var/log/procmail.log&lt;br /&gt;
 INCLUDERC=/etc/procmailrcs/_spamfilter&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
The &amp;quot;_spamfilter&amp;quot; include does the actual collection:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# The lock file ensures that only 1 spamassassin invocation happens&lt;br /&gt;
 # at 1 time, to keep the load down.&lt;br /&gt;
 #&lt;br /&gt;
 :0fw: spamassassin.lock&lt;br /&gt;
 * &amp;amp;lt; 256000&lt;br /&gt;
 | /usr/bin/spamassassin&lt;br /&gt;
 &lt;br /&gt;
 # Mails with a score of 15 or higher are almost certainly spam (with 0.05%&lt;br /&gt;
 # false positives according to rules/STATISTICS.txt). Let&#039;s put them in a&lt;br /&gt;
 # different mbox. (This one is optional.)&lt;br /&gt;
 :0:&lt;br /&gt;
 * ^X-Spam-Level: \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*&lt;br /&gt;
 /local/mailcopy/almost-certainly-spam&lt;br /&gt;
 &lt;br /&gt;
 # Work around procmail bug: any output on stderr will cause the &amp;quot;F&amp;quot; in &amp;quot;From&amp;quot;&lt;br /&gt;
 # to be dropped.  This will re-add it.&lt;br /&gt;
 :0&lt;br /&gt;
 * ^^rom[ ]&lt;br /&gt;
 {&lt;br /&gt;
    LOG=&amp;quot;*** Dropped F off From_ header! Fixing up. &amp;quot;&lt;br /&gt;
 &lt;br /&gt;
   :0 fhw&lt;br /&gt;
   | sed -e &#039;1s/^/F/&#039;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 :0 c&lt;br /&gt;
 /local/mailcopy/unconfirmed-ham&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Notes &amp;amp;amp; Other Resources ==&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to run `newaliases` (or equivalent) after you alter your configuration if appropriate.&lt;br /&gt;
&lt;br /&gt;
* [[SpamScore2Priority]]&lt;br /&gt;
* [http://pm-doc.sourceforge.net/pm-tips-body.html#procmail_flags Procmail flags documentation].&lt;/div&gt;</summary>
		<author><name>Medea61</name></author>
	</entry>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=SpamFiltering&amp;diff=26283</id>
		<title>SpamFiltering</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=SpamFiltering&amp;diff=26283"/>
		<updated>2016-07-19T16:26:03Z</updated>

		<summary type="html">&lt;p&gt;Medea61: /* b. Pre-filtered mail + Scrip =&amp;amp;gt; Queue */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Spam Filtering =&lt;br /&gt;
&lt;br /&gt;
By moving all SPAM to a single queue, you can easily purge (shred) it periodically. You might also take the opportunity to purge any RT users who do not have a ticket associated with them.&lt;br /&gt;
&lt;br /&gt;
Please find documented below 6 setups for processing spam (1a-1c, 2a-2c). In general, you want to filter your messages at the MTA, before they get RT if you can.&lt;br /&gt;
&lt;br /&gt;
The list archives also contain a number of [http://www.gossamer-threads.com/lists/rt/users/87056?search_string=Spam filtering in RT;#87056 useful tips]&lt;br /&gt;
&lt;br /&gt;
== 0. Pre-filtering &amp;amp;amp; scoring messages ==&lt;br /&gt;
&lt;br /&gt;
There are a number of ways of doing so, such as procmail or [http://pthbb.org/manual/software/mailfilter mailfilter] which can do other somewhat-RT-specific pre-processing as well.&lt;br /&gt;
&lt;br /&gt;
== 1. Pre-filtered mail ==&lt;br /&gt;
&lt;br /&gt;
There are several options for processing messages once scored:&lt;br /&gt;
&lt;br /&gt;
=== a. Pre-filtered mail + ::Filter::SpamAssassin (=&amp;amp;gt; Spam Queue) ===&lt;br /&gt;
&lt;br /&gt;
http://codepad.org/HQmnr0AG based on&lt;br /&gt;
&lt;br /&gt;
http://documentroot.com/SpamAssassin.pm based on RT::Interface::Email::Filter::SpamAssassin from 3.8.1&lt;br /&gt;
&lt;br /&gt;
This updated version of the filter provides several options for handling potential spam, such as rejecting all messages above a certain score, and filing others in a SPAM queue.&lt;br /&gt;
&lt;br /&gt;
=== b. Pre-filtered mail + Scrip =&amp;amp;gt; Queue ===&lt;br /&gt;
&lt;br /&gt;
In the example below a score of 5 or more is needed. Edit preparation code if you want to modify the level.&lt;br /&gt;
&lt;br /&gt;
Create new Scrip using following information:&lt;br /&gt;
&lt;br /&gt;
*Condition: On Create &lt;br /&gt;
*Action: User Defined &lt;br /&gt;
*Custom action preparation code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 # Match ***** level spam. You might want to set this higher/lower if needed&lt;br /&gt;
 my $match = &#039;\*\*\*\*\*&#039;;&lt;br /&gt;
 my $inMessage = $self-&amp;amp;gt;TransactionObj-&amp;amp;gt;Attachments-&amp;amp;gt;First;&lt;br /&gt;
 return 0 if (!$inMessage);  # if no message attachment - assume web UI&lt;br /&gt;
 return 0 if (!$inMessage-&amp;amp;gt;GetHeader(&#039;Received&#039;));  # exit if not email message&lt;br /&gt;
 &lt;br /&gt;
 my $spamLevel = $inMessage-&amp;amp;gt;GetHeader(&#039;X-Spam-Level&#039;);&lt;br /&gt;
 return ( $spamLevel !~ /$match/i ) ? 0 : 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Custom action cleanup code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 my $newqueue = &#039;spam&#039;;&lt;br /&gt;
 my ($status, $msg) = $self-&amp;amp;gt;TicketObj-&amp;amp;gt;SetQueue($newqueue);&lt;br /&gt;
 return $status ? undef : 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== c. Pre-filtered mail + ProcMail =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
A procmail recipe (for each queue/(correspond|comment) pair) can be used to send spam to a spam queue in RT. Note that:&lt;br /&gt;
&lt;br /&gt;
* the flags bh need to be set so rt-mailgate sees both the body and header of the message.&lt;br /&gt;
* the absence of a second colon so there is no lockfile&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;PATH=/usr/local/bin:/bin/:/usr/bin&lt;br /&gt;
 LOGFILE=/var/log/procmail.log&lt;br /&gt;
 #rt-mailgate has already saved the message in the rt database&lt;br /&gt;
 #set DEFAULT to be somewhere real if you want procmail to save the message elsewhere&lt;br /&gt;
 DEFAULT=/dev/null&lt;br /&gt;
 &lt;br /&gt;
  #Messages &amp;amp;gt;300000 characters proceed to recipient (unlikely to be spam)&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 * &amp;amp;gt; 300000&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue default --action correspond --url http://localhost/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is fired send to spam queue&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 * ^X-Spam-Level: \*\*\*\*\*&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue spam --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is not fired then send to expected destination&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue default --action correspond --url http://localhost/rt/&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Unfiltered messages ===&lt;br /&gt;
&lt;br /&gt;
=== a. Unfiltered mail + ::Filter::SpamAssassin (=&amp;amp;gt; Spam Queue) ===&lt;br /&gt;
&lt;br /&gt;
RT::Interface::Email::Filter::SpamAssassin above (1a) can also pass unscored messages off to SpamAssassin for processing.&lt;br /&gt;
&lt;br /&gt;
=== b. Unfiltered mail + ProcMail &amp;amp;amp; SpamAssassin =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
This procmail recipe is similar to 1c. above, except that it handles previously unscored messages, and accepts many of the rt-mailgate parameters as environment variables so that it may be easily used with multiple aliases.&lt;br /&gt;
&lt;br /&gt;
Aliases:&lt;br /&gt;
&lt;br /&gt;
 rt: &amp;quot;|/usr/local/bin/procmail -m ACTION=correspond QUEUE=General /usr/local/etc/procmail/rt-deliver.rc&amp;quot;&lt;br /&gt;
 rt-comment: &amp;quot;|/usr/local/bin/procmail -m ACTION=comment QUEUE=General /usr/local/etc/procmail/rt-deliver.rc&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
/usr/local/etc/procmail/rt-deliver.rc:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#Messages &amp;amp;gt;300000 characters proceed to recipient (unlikely to be spam)&lt;br /&gt;
 :0w&lt;br /&gt;
 * &amp;amp;gt; 300000&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue $QUEUE --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #Is it spam?&lt;br /&gt;
 :0fw: spamassassin.lock&lt;br /&gt;
 * &amp;amp;lt; 300000&lt;br /&gt;
 | /usr/local/bin/spamc&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is fired send to spam queue&lt;br /&gt;
 :0w&lt;br /&gt;
 * ^X-Spam-Status: Yes&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue Spam --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is not fired then send to expected destination&lt;br /&gt;
 :0w&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue $QUEUE --action $ACTION --url http://localhost/rt/&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== c. ProcMail + SpamAssassin + Scrip =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
http://www.soundwave.net/~wmono/rt/&lt;br /&gt;
&lt;br /&gt;
== 3. Mis-handled messages ==&lt;br /&gt;
&lt;br /&gt;
=== a. False positives: Greylist ===&lt;br /&gt;
&lt;br /&gt;
2c above outlines a general (non-procmail specific) setup (steps 1 through 6 for RT) to automatically greylist suspect messages. Legitimate requestors may reply to an autoresponse and have their misfiled message requeued.&lt;br /&gt;
&lt;br /&gt;
=== b. False negatives: QuickSpamhandler ===&lt;br /&gt;
&lt;br /&gt;
Note: [[QuickSpamHandler]] seems to no longer be available. The [http://search.cpan.org/~ruz/RT-Extension-ReportSpam-0.02/lib/RT/Extension/ReportSpam.pm RT::Extension::ReportSpam] is fairly similar though.&lt;br /&gt;
&lt;br /&gt;
This extension provides a few tools that can be used for manual triage of SPAM in low-traffic installation, or handling the odd message that leaks through your automated filters:&lt;br /&gt;
&lt;br /&gt;
* Adds alternate forms of the &amp;quot;Unowned Tickets&amp;quot; and &amp;quot;My Tickets&amp;quot; global searches, which exclude messages in the spam queue.&lt;br /&gt;
* Adds a link to the &amp;quot;Search - Unowned Tickets&amp;quot; query which permits you to instantly vanquish a ticket if the subject is sufficient to convince you the message is SPAM.&lt;br /&gt;
* Adds a link to the Ticket tool bar that will instantly vanquish the displayed ticket.&lt;br /&gt;
&lt;br /&gt;
Vanquished tickets are moved to a designated SPAM queue; the default is named &amp;quot;Possible SPAM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Installation ====&lt;br /&gt;
&lt;br /&gt;
* Download the [http://zephyrgeek.qatar.cmu.edu/RT/QuickSpamHandler.tgz archive]&lt;br /&gt;
* Unpack it&lt;br /&gt;
* ./configure&lt;br /&gt;
* make install&lt;br /&gt;
* Read and act on the output from the previous command.&lt;br /&gt;
&lt;br /&gt;
Really, the only tricky bit is the database update. If I ever figure out a better way to do this I&#039;ll make sure to update the archive. Hopefully someone will find this useful. If you do, please drop me a line!&lt;br /&gt;
&lt;br /&gt;
=== c. False negatives: Bookmarklet ===&lt;br /&gt;
&lt;br /&gt;
An alternative to QuickSpamHandler above, this bookmarklet moves the displayed ticket to the spam queue (change 12 to the appropriate ID for your queue), and sets the status to rejected.&lt;br /&gt;
&lt;br /&gt;
 javascript:self.location=self.location+&#039;&amp;amp;amp;Status=resolved&amp;amp;amp;Queue=12&#039;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Thus you can distinguish messages which you have already decided are spam, from those which are automatically filed into that queue.&lt;br /&gt;
&lt;br /&gt;
== Collect spam/ham for training with procmail ==&lt;br /&gt;
&lt;br /&gt;
In /etc/postfix, I am maintaining a file named rt-aliases. It contains, for every queue:&lt;br /&gt;
&lt;br /&gt;
 rt:         &amp;quot;|/usr/bin/procmail -m /etc/procmailrcs/general&amp;quot;&lt;br /&gt;
 rt-comment: &amp;quot;|/usr/bin/procmail -m /etc/procmailrcs/general-comment&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
in /etc/procmailrcs, the file &amp;quot;general&amp;quot; looks like:&lt;br /&gt;
&lt;br /&gt;
 PATH=/usr/local/bin:/bin:/usr/bin&lt;br /&gt;
 LOGFILE=/var/log/procmail.log&lt;br /&gt;
 INCLUDERC=/etc/procmailrcs/_spamfilter&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
The &amp;quot;_spamfilter&amp;quot; include does the actual collection:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# The lock file ensures that only 1 spamassassin invocation happens&lt;br /&gt;
 # at 1 time, to keep the load down.&lt;br /&gt;
 #&lt;br /&gt;
 :0fw: spamassassin.lock&lt;br /&gt;
 * &amp;amp;lt; 256000&lt;br /&gt;
 | /usr/bin/spamassassin&lt;br /&gt;
 &lt;br /&gt;
 # Mails with a score of 15 or higher are almost certainly spam (with 0.05%&lt;br /&gt;
 # false positives according to rules/STATISTICS.txt). Let&#039;s put them in a&lt;br /&gt;
 # different mbox. (This one is optional.)&lt;br /&gt;
 :0:&lt;br /&gt;
 * ^X-Spam-Level: \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*&lt;br /&gt;
 /local/mailcopy/almost-certainly-spam&lt;br /&gt;
 &lt;br /&gt;
 # Work around procmail bug: any output on stderr will cause the &amp;quot;F&amp;quot; in &amp;quot;From&amp;quot;&lt;br /&gt;
 # to be dropped.  This will re-add it.&lt;br /&gt;
 :0&lt;br /&gt;
 * ^^rom[ ]&lt;br /&gt;
 {&lt;br /&gt;
    LOG=&amp;quot;*** Dropped F off From_ header! Fixing up. &amp;quot;&lt;br /&gt;
 &lt;br /&gt;
   :0 fhw&lt;br /&gt;
   | sed -e &#039;1s/^/F/&#039;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 :0 c&lt;br /&gt;
 /local/mailcopy/unconfirmed-ham&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Notes &amp;amp;amp; Other Resources ==&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to run `newaliases` (or equivalent) after you alter your configuration if appropriate.&lt;br /&gt;
&lt;br /&gt;
* [[SpamScore2Priority]]&lt;br /&gt;
* [http://pm-doc.sourceforge.net/pm-tips-body.html#procmail_flags Procmail flags documentation].&lt;/div&gt;</summary>
		<author><name>Medea61</name></author>
	</entry>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=SpamFiltering&amp;diff=26282</id>
		<title>SpamFiltering</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=SpamFiltering&amp;diff=26282"/>
		<updated>2016-07-19T16:23:38Z</updated>

		<summary type="html">&lt;p&gt;Medea61: Undo revision 26281 by Medea61 (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Spam Filtering =&lt;br /&gt;
&lt;br /&gt;
By moving all SPAM to a single queue, you can easily purge (shred) it periodically. You might also take the opportunity to purge any RT users who do not have a ticket associated with them.&lt;br /&gt;
&lt;br /&gt;
Please find documented below 6 setups for processing spam (1a-1c, 2a-2c). In general, you want to filter your messages at the MTA, before they get RT if you can.&lt;br /&gt;
&lt;br /&gt;
The list archives also contain a number of [http://www.gossamer-threads.com/lists/rt/users/87056?search_string=Spam filtering in RT;#87056 useful tips]&lt;br /&gt;
&lt;br /&gt;
== 0. Pre-filtering &amp;amp;amp; scoring messages ==&lt;br /&gt;
&lt;br /&gt;
There are a number of ways of doing so, such as procmail or [http://pthbb.org/manual/software/mailfilter mailfilter] which can do other somewhat-RT-specific pre-processing as well.&lt;br /&gt;
&lt;br /&gt;
== 1. Pre-filtered mail ==&lt;br /&gt;
&lt;br /&gt;
There are several options for processing messages once scored:&lt;br /&gt;
&lt;br /&gt;
=== a. Pre-filtered mail + ::Filter::SpamAssassin (=&amp;amp;gt; Spam Queue) ===&lt;br /&gt;
&lt;br /&gt;
http://codepad.org/HQmnr0AG based on&lt;br /&gt;
&lt;br /&gt;
http://documentroot.com/SpamAssassin.pm based on RT::Interface::Email::Filter::SpamAssassin from 3.8.1&lt;br /&gt;
&lt;br /&gt;
This updated version of the filter provides several options for handling potential spam, such as rejecting all messages above a certain score, and filing others in a SPAM queue.&lt;br /&gt;
&lt;br /&gt;
=== b. Pre-filtered mail + Scrip =&amp;amp;gt; Queue ===&lt;br /&gt;
&lt;br /&gt;
In the example below a score of 5 or more is needed. Edit preparation code if you want to modify the level.&lt;br /&gt;
&lt;br /&gt;
Create new Scrip using following information:&lt;br /&gt;
&lt;br /&gt;
*Condition: On Create *Action: User Defined *Custom action preparation code:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# Match ***** level spam. You might want to set this higher/lower if needed&lt;br /&gt;
 my $match = &#039;\*\*\*\*\*&#039;;&lt;br /&gt;
 my $inMessage = $self-&amp;amp;gt;TransactionObj-&amp;amp;gt;Attachments-&amp;amp;gt;First;&lt;br /&gt;
 return 0 if (!$inMessage);  # if no message attachment - assume web UI&lt;br /&gt;
 return 0 if (!$inMessage-&amp;amp;gt;GetHeader(&#039;Received&#039;));  # exit if not email message&lt;br /&gt;
 &lt;br /&gt;
 my $spamLevel = $inMessage-&amp;amp;gt;GetHeader(&#039;X-Spam-Level&#039;);&lt;br /&gt;
 return ( $spamLevel !~ /$match/i ) ? 0 : 1;&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Custom action cleanup code:&lt;br /&gt;
&lt;br /&gt;
 my $newqueue = &#039;spam&#039;;&lt;br /&gt;
 my ($status, $msg) = $self-&amp;amp;gt;TicketObj-&amp;amp;gt;SetQueue($newqueue);&lt;br /&gt;
 return $status ? undef : 1;&lt;br /&gt;
&lt;br /&gt;
=== c. Pre-filtered mail + ProcMail =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
A procmail recipe (for each queue/(correspond|comment) pair) can be used to send spam to a spam queue in RT. Note that:&lt;br /&gt;
&lt;br /&gt;
* the flags bh need to be set so rt-mailgate sees both the body and header of the message.&lt;br /&gt;
* the absence of a second colon so there is no lockfile&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;PATH=/usr/local/bin:/bin/:/usr/bin&lt;br /&gt;
 LOGFILE=/var/log/procmail.log&lt;br /&gt;
 #rt-mailgate has already saved the message in the rt database&lt;br /&gt;
 #set DEFAULT to be somewhere real if you want procmail to save the message elsewhere&lt;br /&gt;
 DEFAULT=/dev/null&lt;br /&gt;
 &lt;br /&gt;
  #Messages &amp;amp;gt;300000 characters proceed to recipient (unlikely to be spam)&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 * &amp;amp;gt; 300000&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue default --action correspond --url http://localhost/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is fired send to spam queue&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 * ^X-Spam-Level: \*\*\*\*\*&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue spam --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is not fired then send to expected destination&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue default --action correspond --url http://localhost/rt/&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Unfiltered messages ===&lt;br /&gt;
&lt;br /&gt;
=== a. Unfiltered mail + ::Filter::SpamAssassin (=&amp;amp;gt; Spam Queue) ===&lt;br /&gt;
&lt;br /&gt;
RT::Interface::Email::Filter::SpamAssassin above (1a) can also pass unscored messages off to SpamAssassin for processing.&lt;br /&gt;
&lt;br /&gt;
=== b. Unfiltered mail + ProcMail &amp;amp;amp; SpamAssassin =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
This procmail recipe is similar to 1c. above, except that it handles previously unscored messages, and accepts many of the rt-mailgate parameters as environment variables so that it may be easily used with multiple aliases.&lt;br /&gt;
&lt;br /&gt;
Aliases:&lt;br /&gt;
&lt;br /&gt;
 rt: &amp;quot;|/usr/local/bin/procmail -m ACTION=correspond QUEUE=General /usr/local/etc/procmail/rt-deliver.rc&amp;quot;&lt;br /&gt;
 rt-comment: &amp;quot;|/usr/local/bin/procmail -m ACTION=comment QUEUE=General /usr/local/etc/procmail/rt-deliver.rc&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
/usr/local/etc/procmail/rt-deliver.rc:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#Messages &amp;amp;gt;300000 characters proceed to recipient (unlikely to be spam)&lt;br /&gt;
 :0w&lt;br /&gt;
 * &amp;amp;gt; 300000&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue $QUEUE --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #Is it spam?&lt;br /&gt;
 :0fw: spamassassin.lock&lt;br /&gt;
 * &amp;amp;lt; 300000&lt;br /&gt;
 | /usr/local/bin/spamc&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is fired send to spam queue&lt;br /&gt;
 :0w&lt;br /&gt;
 * ^X-Spam-Status: Yes&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue Spam --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is not fired then send to expected destination&lt;br /&gt;
 :0w&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue $QUEUE --action $ACTION --url http://localhost/rt/&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== c. ProcMail + SpamAssassin + Scrip =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
http://www.soundwave.net/~wmono/rt/&lt;br /&gt;
&lt;br /&gt;
== 3. Mis-handled messages ==&lt;br /&gt;
&lt;br /&gt;
=== a. False positives: Greylist ===&lt;br /&gt;
&lt;br /&gt;
2c above outlines a general (non-procmail specific) setup (steps 1 through 6 for RT) to automatically greylist suspect messages. Legitimate requestors may reply to an autoresponse and have their misfiled message requeued.&lt;br /&gt;
&lt;br /&gt;
=== b. False negatives: QuickSpamhandler ===&lt;br /&gt;
&lt;br /&gt;
Note: [[QuickSpamHandler]] seems to no longer be available. The [http://search.cpan.org/~ruz/RT-Extension-ReportSpam-0.02/lib/RT/Extension/ReportSpam.pm RT::Extension::ReportSpam] is fairly similar though.&lt;br /&gt;
&lt;br /&gt;
This extension provides a few tools that can be used for manual triage of SPAM in low-traffic installation, or handling the odd message that leaks through your automated filters:&lt;br /&gt;
&lt;br /&gt;
* Adds alternate forms of the &amp;quot;Unowned Tickets&amp;quot; and &amp;quot;My Tickets&amp;quot; global searches, which exclude messages in the spam queue.&lt;br /&gt;
* Adds a link to the &amp;quot;Search - Unowned Tickets&amp;quot; query which permits you to instantly vanquish a ticket if the subject is sufficient to convince you the message is SPAM.&lt;br /&gt;
* Adds a link to the Ticket tool bar that will instantly vanquish the displayed ticket.&lt;br /&gt;
&lt;br /&gt;
Vanquished tickets are moved to a designated SPAM queue; the default is named &amp;quot;Possible SPAM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Installation ====&lt;br /&gt;
&lt;br /&gt;
* Download the [http://zephyrgeek.qatar.cmu.edu/RT/QuickSpamHandler.tgz archive]&lt;br /&gt;
* Unpack it&lt;br /&gt;
* ./configure&lt;br /&gt;
* make install&lt;br /&gt;
* Read and act on the output from the previous command.&lt;br /&gt;
&lt;br /&gt;
Really, the only tricky bit is the database update. If I ever figure out a better way to do this I&#039;ll make sure to update the archive. Hopefully someone will find this useful. If you do, please drop me a line!&lt;br /&gt;
&lt;br /&gt;
=== c. False negatives: Bookmarklet ===&lt;br /&gt;
&lt;br /&gt;
An alternative to QuickSpamHandler above, this bookmarklet moves the displayed ticket to the spam queue (change 12 to the appropriate ID for your queue), and sets the status to rejected.&lt;br /&gt;
&lt;br /&gt;
 javascript:self.location=self.location+&#039;&amp;amp;amp;Status=resolved&amp;amp;amp;Queue=12&#039;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Thus you can distinguish messages which you have already decided are spam, from those which are automatically filed into that queue.&lt;br /&gt;
&lt;br /&gt;
== Collect spam/ham for training with procmail ==&lt;br /&gt;
&lt;br /&gt;
In /etc/postfix, I am maintaining a file named rt-aliases. It contains, for every queue:&lt;br /&gt;
&lt;br /&gt;
 rt:         &amp;quot;|/usr/bin/procmail -m /etc/procmailrcs/general&amp;quot;&lt;br /&gt;
 rt-comment: &amp;quot;|/usr/bin/procmail -m /etc/procmailrcs/general-comment&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
in /etc/procmailrcs, the file &amp;quot;general&amp;quot; looks like:&lt;br /&gt;
&lt;br /&gt;
 PATH=/usr/local/bin:/bin:/usr/bin&lt;br /&gt;
 LOGFILE=/var/log/procmail.log&lt;br /&gt;
 INCLUDERC=/etc/procmailrcs/_spamfilter&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
The &amp;quot;_spamfilter&amp;quot; include does the actual collection:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# The lock file ensures that only 1 spamassassin invocation happens&lt;br /&gt;
 # at 1 time, to keep the load down.&lt;br /&gt;
 #&lt;br /&gt;
 :0fw: spamassassin.lock&lt;br /&gt;
 * &amp;amp;lt; 256000&lt;br /&gt;
 | /usr/bin/spamassassin&lt;br /&gt;
 &lt;br /&gt;
 # Mails with a score of 15 or higher are almost certainly spam (with 0.05%&lt;br /&gt;
 # false positives according to rules/STATISTICS.txt). Let&#039;s put them in a&lt;br /&gt;
 # different mbox. (This one is optional.)&lt;br /&gt;
 :0:&lt;br /&gt;
 * ^X-Spam-Level: \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*&lt;br /&gt;
 /local/mailcopy/almost-certainly-spam&lt;br /&gt;
 &lt;br /&gt;
 # Work around procmail bug: any output on stderr will cause the &amp;quot;F&amp;quot; in &amp;quot;From&amp;quot;&lt;br /&gt;
 # to be dropped.  This will re-add it.&lt;br /&gt;
 :0&lt;br /&gt;
 * ^^rom[ ]&lt;br /&gt;
 {&lt;br /&gt;
    LOG=&amp;quot;*** Dropped F off From_ header! Fixing up. &amp;quot;&lt;br /&gt;
 &lt;br /&gt;
   :0 fhw&lt;br /&gt;
   | sed -e &#039;1s/^/F/&#039;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 :0 c&lt;br /&gt;
 /local/mailcopy/unconfirmed-ham&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Notes &amp;amp;amp; Other Resources ==&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to run `newaliases` (or equivalent) after you alter your configuration if appropriate.&lt;br /&gt;
&lt;br /&gt;
* [[SpamScore2Priority]]&lt;br /&gt;
* [http://pm-doc.sourceforge.net/pm-tips-body.html#procmail_flags Procmail flags documentation].&lt;/div&gt;</summary>
		<author><name>Medea61</name></author>
	</entry>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=SpamFiltering&amp;diff=26281</id>
		<title>SpamFiltering</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=SpamFiltering&amp;diff=26281"/>
		<updated>2016-07-19T16:23:21Z</updated>

		<summary type="html">&lt;p&gt;Medea61: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Spam Filtering =&lt;br /&gt;
&lt;br /&gt;
By moving all SPAM to a single queue, you can easily purge (shred) it periodically. You might also take the opportunity to purge any RT users who do not have a ticket associated with them.&lt;br /&gt;
&lt;br /&gt;
Please find documented below 6 setups for processing spam (1a-1c, 2a-2c). In general, you want to filter your messages at the MTA, before they get RT if you can.&lt;br /&gt;
&lt;br /&gt;
The list archives also contain a number of [http://www.gossamer-threads.com/lists/rt/users/87056?search_string=Spam filtering in RT;#87056 useful tips]&lt;br /&gt;
&lt;br /&gt;
== 0. Pre-filtering &amp;amp;amp; scoring messages ==&lt;br /&gt;
&lt;br /&gt;
There are a number of ways of doing so, such as procmail or [http://pthbb.org/manual/software/mailfilter mailfilter] which can do other somewhat-RT-specific pre-processing as well.&lt;br /&gt;
&lt;br /&gt;
== 1. Pre-filtered mail ==&lt;br /&gt;
&lt;br /&gt;
There are several options for processing messages once scored:&lt;br /&gt;
&lt;br /&gt;
=== a. Pre-filtered mail + ::Filter::SpamAssassin (=&amp;amp;gt; Spam Queue) ===&lt;br /&gt;
&lt;br /&gt;
http://codepad.org/HQmnr0AG based on&lt;br /&gt;
&lt;br /&gt;
http://documentroot.com/SpamAssassin.pm based on RT::Interface::Email::Filter::SpamAssassin from 3.8.1&lt;br /&gt;
&lt;br /&gt;
This updated version of the filter provides several options for handling potential spam, such as rejecting all messages above a certain score, and filing others in a SPAM queue.&lt;br /&gt;
&lt;br /&gt;
=== b. Pre-filtered mail + Scrip =&amp;amp;gt; Queue ===&lt;br /&gt;
&lt;br /&gt;
In the example below a score of 5 or more is needed. Edit preparation code if you want to modify the level.&lt;br /&gt;
&lt;br /&gt;
Create new Scrip using following information:&lt;br /&gt;
&lt;br /&gt;
*Condition: On Create &lt;br /&gt;
*Action: User Defined &lt;br /&gt;
*Custom action preparation code: &amp;lt;code&amp;gt;&lt;br /&gt;
# Match ***** level spam. You might want to set this higher/lower if needed&lt;br /&gt;
my $match = &#039;\*\*\*\*\*&#039;;&lt;br /&gt;
my $inMessage = $self-&amp;amp;gt;TransactionObj-&amp;amp;gt;Attachments-&amp;amp;gt;First;&lt;br /&gt;
return 0 if (!$inMessage);  # if no message attachment - assume web UI&lt;br /&gt;
return 0 if (!$inMessage-&amp;amp;gt;GetHeader(&#039;Received&#039;));  # exit if not email message&lt;br /&gt;
 &lt;br /&gt;
my $spamLevel = $inMessage-&amp;amp;gt;GetHeader(&#039;X-Spam-Level&#039;);&lt;br /&gt;
return ( $spamLevel !~ /$match/i ) ? 0 : 1;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Custom action cleanup code: &amp;lt;code&amp;gt;&lt;br /&gt;
my $newqueue = &#039;spam&#039;;&lt;br /&gt;
my ($status, $msg) = $self-&amp;amp;gt;TicketObj-&amp;amp;gt;SetQueue($newqueue);&lt;br /&gt;
return $status ? undef : 1;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== c. Pre-filtered mail + ProcMail =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
A procmail recipe (for each queue/(correspond|comment) pair) can be used to send spam to a spam queue in RT. Note that:&lt;br /&gt;
&lt;br /&gt;
* the flags bh need to be set so rt-mailgate sees both the body and header of the message.&lt;br /&gt;
* the absence of a second colon so there is no lockfile&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;PATH=/usr/local/bin:/bin/:/usr/bin&lt;br /&gt;
 LOGFILE=/var/log/procmail.log&lt;br /&gt;
 #rt-mailgate has already saved the message in the rt database&lt;br /&gt;
 #set DEFAULT to be somewhere real if you want procmail to save the message elsewhere&lt;br /&gt;
 DEFAULT=/dev/null&lt;br /&gt;
 &lt;br /&gt;
  #Messages &amp;amp;gt;300000 characters proceed to recipient (unlikely to be spam)&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 * &amp;amp;gt; 300000&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue default --action correspond --url http://localhost/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is fired send to spam queue&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 * ^X-Spam-Level: \*\*\*\*\*&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue spam --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is not fired then send to expected destination&lt;br /&gt;
 #:0fwbh&lt;br /&gt;
 :0wbh&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue default --action correspond --url http://localhost/rt/&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Unfiltered messages ===&lt;br /&gt;
&lt;br /&gt;
=== a. Unfiltered mail + ::Filter::SpamAssassin (=&amp;amp;gt; Spam Queue) ===&lt;br /&gt;
&lt;br /&gt;
RT::Interface::Email::Filter::SpamAssassin above (1a) can also pass unscored messages off to SpamAssassin for processing.&lt;br /&gt;
&lt;br /&gt;
=== b. Unfiltered mail + ProcMail &amp;amp;amp; SpamAssassin =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
This procmail recipe is similar to 1c. above, except that it handles previously unscored messages, and accepts many of the rt-mailgate parameters as environment variables so that it may be easily used with multiple aliases.&lt;br /&gt;
&lt;br /&gt;
Aliases:&lt;br /&gt;
&lt;br /&gt;
 rt: &amp;quot;|/usr/local/bin/procmail -m ACTION=correspond QUEUE=General /usr/local/etc/procmail/rt-deliver.rc&amp;quot;&lt;br /&gt;
 rt-comment: &amp;quot;|/usr/local/bin/procmail -m ACTION=comment QUEUE=General /usr/local/etc/procmail/rt-deliver.rc&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
/usr/local/etc/procmail/rt-deliver.rc:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;#Messages &amp;amp;gt;300000 characters proceed to recipient (unlikely to be spam)&lt;br /&gt;
 :0w&lt;br /&gt;
 * &amp;amp;gt; 300000&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue $QUEUE --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #Is it spam?&lt;br /&gt;
 :0fw: spamassassin.lock&lt;br /&gt;
 * &amp;amp;lt; 300000&lt;br /&gt;
 | /usr/local/bin/spamc&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is fired send to spam queue&lt;br /&gt;
 :0w&lt;br /&gt;
 * ^X-Spam-Status: Yes&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue Spam --action correspond --url http://localhost/rt/&lt;br /&gt;
 &lt;br /&gt;
 #if the spam trigger is not fired then send to expected destination&lt;br /&gt;
 :0w&lt;br /&gt;
 | /usr/local/rt3/bin/rt-mailgate --queue $QUEUE --action $ACTION --url http://localhost/rt/&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== c. ProcMail + SpamAssassin + Scrip =&amp;amp;gt; Spam Queue ===&lt;br /&gt;
&lt;br /&gt;
http://www.soundwave.net/~wmono/rt/&lt;br /&gt;
&lt;br /&gt;
== 3. Mis-handled messages ==&lt;br /&gt;
&lt;br /&gt;
=== a. False positives: Greylist ===&lt;br /&gt;
&lt;br /&gt;
2c above outlines a general (non-procmail specific) setup (steps 1 through 6 for RT) to automatically greylist suspect messages. Legitimate requestors may reply to an autoresponse and have their misfiled message requeued.&lt;br /&gt;
&lt;br /&gt;
=== b. False negatives: QuickSpamhandler ===&lt;br /&gt;
&lt;br /&gt;
Note: [[QuickSpamHandler]] seems to no longer be available. The [http://search.cpan.org/~ruz/RT-Extension-ReportSpam-0.02/lib/RT/Extension/ReportSpam.pm RT::Extension::ReportSpam] is fairly similar though.&lt;br /&gt;
&lt;br /&gt;
This extension provides a few tools that can be used for manual triage of SPAM in low-traffic installation, or handling the odd message that leaks through your automated filters:&lt;br /&gt;
&lt;br /&gt;
* Adds alternate forms of the &amp;quot;Unowned Tickets&amp;quot; and &amp;quot;My Tickets&amp;quot; global searches, which exclude messages in the spam queue.&lt;br /&gt;
* Adds a link to the &amp;quot;Search - Unowned Tickets&amp;quot; query which permits you to instantly vanquish a ticket if the subject is sufficient to convince you the message is SPAM.&lt;br /&gt;
* Adds a link to the Ticket tool bar that will instantly vanquish the displayed ticket.&lt;br /&gt;
&lt;br /&gt;
Vanquished tickets are moved to a designated SPAM queue; the default is named &amp;quot;Possible SPAM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Installation ====&lt;br /&gt;
&lt;br /&gt;
* Download the [http://zephyrgeek.qatar.cmu.edu/RT/QuickSpamHandler.tgz archive]&lt;br /&gt;
* Unpack it&lt;br /&gt;
* ./configure&lt;br /&gt;
* make install&lt;br /&gt;
* Read and act on the output from the previous command.&lt;br /&gt;
&lt;br /&gt;
Really, the only tricky bit is the database update. If I ever figure out a better way to do this I&#039;ll make sure to update the archive. Hopefully someone will find this useful. If you do, please drop me a line!&lt;br /&gt;
&lt;br /&gt;
=== c. False negatives: Bookmarklet ===&lt;br /&gt;
&lt;br /&gt;
An alternative to QuickSpamHandler above, this bookmarklet moves the displayed ticket to the spam queue (change 12 to the appropriate ID for your queue), and sets the status to rejected.&lt;br /&gt;
&lt;br /&gt;
 javascript:self.location=self.location+&#039;&amp;amp;amp;Status=resolved&amp;amp;amp;Queue=12&#039;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Thus you can distinguish messages which you have already decided are spam, from those which are automatically filed into that queue.&lt;br /&gt;
&lt;br /&gt;
== Collect spam/ham for training with procmail ==&lt;br /&gt;
&lt;br /&gt;
In /etc/postfix, I am maintaining a file named rt-aliases. It contains, for every queue:&lt;br /&gt;
&lt;br /&gt;
 rt:         &amp;quot;|/usr/bin/procmail -m /etc/procmailrcs/general&amp;quot;&lt;br /&gt;
 rt-comment: &amp;quot;|/usr/bin/procmail -m /etc/procmailrcs/general-comment&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
in /etc/procmailrcs, the file &amp;quot;general&amp;quot; looks like:&lt;br /&gt;
&lt;br /&gt;
 PATH=/usr/local/bin:/bin:/usr/bin&lt;br /&gt;
 LOGFILE=/var/log/procmail.log&lt;br /&gt;
 INCLUDERC=/etc/procmailrcs/_spamfilter&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
The &amp;quot;_spamfilter&amp;quot; include does the actual collection:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# The lock file ensures that only 1 spamassassin invocation happens&lt;br /&gt;
 # at 1 time, to keep the load down.&lt;br /&gt;
 #&lt;br /&gt;
 :0fw: spamassassin.lock&lt;br /&gt;
 * &amp;amp;lt; 256000&lt;br /&gt;
 | /usr/bin/spamassassin&lt;br /&gt;
 &lt;br /&gt;
 # Mails with a score of 15 or higher are almost certainly spam (with 0.05%&lt;br /&gt;
 # false positives according to rules/STATISTICS.txt). Let&#039;s put them in a&lt;br /&gt;
 # different mbox. (This one is optional.)&lt;br /&gt;
 :0:&lt;br /&gt;
 * ^X-Spam-Level: \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*&lt;br /&gt;
 /local/mailcopy/almost-certainly-spam&lt;br /&gt;
 &lt;br /&gt;
 # Work around procmail bug: any output on stderr will cause the &amp;quot;F&amp;quot; in &amp;quot;From&amp;quot;&lt;br /&gt;
 # to be dropped.  This will re-add it.&lt;br /&gt;
 :0&lt;br /&gt;
 * ^^rom[ ]&lt;br /&gt;
 {&lt;br /&gt;
    LOG=&amp;quot;*** Dropped F off From_ header! Fixing up. &amp;quot;&lt;br /&gt;
 &lt;br /&gt;
   :0 fhw&lt;br /&gt;
   | sed -e &#039;1s/^/F/&#039;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 :0 c&lt;br /&gt;
 /local/mailcopy/unconfirmed-ham&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Notes &amp;amp;amp; Other Resources ==&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to run `newaliases` (or equivalent) after you alter your configuration if appropriate.&lt;br /&gt;
&lt;br /&gt;
* [[SpamScore2Priority]]&lt;br /&gt;
* [http://pm-doc.sourceforge.net/pm-tips-body.html#procmail_flags Procmail flags documentation].&lt;/div&gt;</summary>
		<author><name>Medea61</name></author>
	</entry>
</feed>