Offering: rt-remind

Today I found rt-remind on the BP FTP server, and made a few small mods, included below.

Use Getopt::Long.
use Pod::Usage
Take (multiple) queue names on the command line.
Take priority-defaults for mail-send on the command line
&formatDate returns ISO-formatted date
Added this POD

Lee Goddard
Internet Application Analysis/Development
European Aviation Safety Agency
Administrative Directorate

T: +49 221 89990 3221
F: +49 221 89990 3721
:: Ottoplat 1, D-50679 Köln, Germany


#!/usr/bin/perl -w

our $DEBUG = 0;
use strict;
use warnings;

=head1 TITLE

rt-remind - reminder RT3 users of their obligations


This script will remind people about tickets they have not responded to
or dealt with in a ‘reasonable’ length of time. In its normal mode it will
tell ticket owners about tickets which have exceeded a given priority.
It also has the ability to tell ticket owners about all their open or new
tickets, with or without stalled tickets.

This is best used with another script to escalate priorities automatically.

You will need to manually configure this script when you install it.

=head1 USAGE

rt-remind [-help | -q[ueue] QueueName1 ... [-q[ueue] QueueNameN] 
[-p[riority] [new=D [open=DD] ] [ -m[ost] |-a[ll] ] ]

If run with no flags, reports on ‘important’ tickets. Command-line arguments and Options are:

=item -q --queue

Name of the RT queue, at least once, or many times. May also be a comma-seperated list.

=item -p --priority

Specify at what priority new or open tickets get included in the report:

--priority new=2 open=2

=item -m --most

Optionally show all open or new tickets

=item -a --all

Optionally show all open, new, or stalled tickets

=item -help

Show this documentation.

The intended use is to run with no flags daily, with the C<-most> flag weekly
and with the C<-all> flag monthly. Or similar.

=head1 EXAMPLE

rt-remind -q CoffeeMachine,SandwichOrders -p new=8 open=8 -a
rt-remind --queue CoffeeMachine



=head1 AUTHOR

Written by T.D.Bishop -in-, July 2003.
Updated by Lee.Goddard -in-, Dec 2005

=head1 CHANGES

=over 4

=item 2005-12-12: lgoddard

Use Getopt::Long.
Use Pod::Usage
Take (multiple) queue names on the command line.
Take priority-defaults for mail-send on the command line
&formatDate returns ISO-formatted date
Added this POD

=item 2003-07-30: TB Bishop
Original version


=head1 TODO

=over 4

=item *

Include queue names in e-mail report

=item *

Use the standard RT mail interface.



use Carp;
use Getopt::Long;
use Pod::Usage;


Location of RT3’s libs

use lib ("/opt/rt3/lib", “/opt/rt3/etc”);

Mappings of users to addresses

This overrides addresses in the RT database

The most useful case is setting an address for Nobody

my %map = (
‘Nobody’ => ‘lee.goddard@easaeuint’,
‘root’ => ‘lee.goddard@easaeuint’,

Address emails should originate from

my $FROM = ‘lee.goddard@easaeuint’; die ‘Read the source to configure’;

The length at which lines will be truncated. 80, or thereabouts looks

best for most people. Setting to 0 will stop lines being truncated.

my $linelen = 80;

Path to sendmail and flags

my $sendmail = "/usr/sbin/sendmail -t ";

Each state can have a priority associated with it.

When a ticket in that state passes the given priority it is added to

the list to be sent out.

my %pri = (
‘new’ => 2,
‘open’ => 7,


my ($showall, $showmost, $help) = (0,0,0);
my @queuenames;

my $result = GetOptions (
‘most’ => $showmost,
‘all’ => $showall,
‘help’ => $help,
‘queue=s’ => @queuenames,
‘priority=s%’ => $pri,

Allow queue names as csv

@queuenames = split(/,/,join(’,’,@queuenames));

if ($help or not (scalar @queuenames)){
pod2usage(-exitstatus => 0, -verbose => 2) ;

Pull in the RT stuff

package RT;
use RT::Interface::CLI qw(CleanEnv GetCurrentUser GetMessageContent loc);
use RT::Date;
use RT::Queue;
use RT::Tickets;


foreach my $queuename (@queuenames){

CleanEnv();						# Clean our the environment
RT::LoadConfig();				# Load the RT configuration
RT::Init();						# Initialise RT
RT::DropSetGIDPermissions();	# Drop any setgid permissions we might have

# Load in the queue
my $queue = new RT::Queue($RT::SystemUser);

my $now = new RT::Date($RT::SystemUser);

# Get hold of the tickets we're after, sorted by priority
my $tickets = new RT::Tickets($RT::SystemUser);
$tickets->LimitStatus(VALUE => 'new');
$tickets->LimitStatus(VALUE => 'open');
$tickets->LimitStatus(VALUE => 'stalled') if $showall;
$tickets->LimitQueue(VALUE => $queue->Id);
$tickets->OrderBy(FIELD => 'Priority', ORDER => 'DESC');
my $user = RT::User->new($RT::SystemUser);

# Sort tickets in to lists for each owner
while (my $Ticket = $tickets->Next) {
	my $email = $map{$user->Name} || $user->EmailAddress;
	push @{$TicketStore{$email}}, $Ticket;


Process tickets for each owner

foreach my $email (keys %TicketStore) {
&doOwner($email, @{$TicketStore{$email}});

Disconnect before we finish off

exit 0;

Subroutine to generate a messages for a given owner and set of tickets.

sub doOwner() {
my ($to, @tickets) = (@_);
# Mail headers
my $msg = “From: $FROM\n”.“To: $to\n”.“Subject: [RT] Outstanding Tickets\n\n”;

if($showall) {
    $msg .= "This is a summary of all open, new, or stalled tickets assigned to:\n";
elsif($showmost) {
    $msg .= "This is a summary of all open or new tickets assigned to:\n";
else {
    $msg .= "These tickets are now considered important and are assigned to:\n";
$msg .= "\n$to\n\n";

# Message table heaer:
$msg .= sprintf "%5s  %-7s %3s  %-20s %-30s\n", "Id", "Status", "Pri", "Date", "Subject";
$msg .= ('-'x($linelen-1))."\n";

my $printmsg = 0; # Flag

# Look through tickets
foreach my $Ticket (@tickets) {
    # Only add ticket if it's over the priority, or we're in -a or -A
    if($Ticket->Priority > $pri{$Ticket->Status} || $showmost || $showall) {
        $printmsg = 1;
        # Use our own date formatting routine
        my($date) = &formatDate($Ticket->CreatedObj->Unix);
        my($line) = sprintf "%5d  %-7s %3d  %-20s %-30s", $Ticket->Id, $Ticket->Status, $Ticket->Priority, $date, $Ticket->Subject;
        # Truncate lines if required
        $line = substr($line, 0, $linelen) if $linelen;
        $msg .= "$line\n";

$msg .= ('-'x($linelen-1))."\n";

# Send the message
if ($printmsg) {
	if ($DEBUG){
		print $msg."\n" 
	} else {
    	open(SENDMAIL, "|$sendmail") || die "Error sending mail: $!";
    	print SENDMAIL $msg;


Smaller than Data::Simple::ISO

sub formatDate() {
my $unixtime = shift;
return “” if $unixtime <= 0; # Return an empty string if we haven’t been given a time
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($unixtime);
$year += 1900; $mon += 1;
return sprintf “%04d-%02d-%02d %02d:%02d:%02d”, $year,$mon,$mday, $hour, $min, $sec;