Mbox2Rt

From Request Tracker Wiki
Jump to navigation Jump to search

This is a piece of code i use to import unix-style mailboxes ( mbox , or whatever you may call them ) into an RT database and keep the threaded nature of the mail in the mailbox, unfortunately it doesn't work very well in importing all email in mailboxes; sometimes (failed in investigating when and why exactly), it only imports parts of a mailbox.... :(

Prerequisites:

  • Mail::Box perl-module
  • an installed RT (at least the 'lib' dir from a RT distribution)
  • a user that can read RT_SiteConfig.pm (otherwise RT will complain)

Caveats:

  • I'm quite new to RT internals, most of this code is inspired on the Gateway-subroutine in RT::Interface::Email.pm, so your mileage may vary
  • if the queue you use this on has an autoreply on create, every ticket that will be created will generate an autoreply
#!/usr/bin/perl
 use strict;
 
 use Getopt::Std;
 
 use Mail::Box::Manager;
 
 #TODO change this to your local RT lib
 use lib qw(/usr/local/rt34/lib);
 use RT;
 
 RT::LoadConfig();
 RT::Init();
 RT::ConnectToDatabase();
 
 my %opts;
 getopts('m:q:fh',\%opts);
 
 if ($opts{'h'}) {
    print <<"";
 Usage: $0 -m <mailbox-file> -q <rt-queue-id> [-f] [-v] [-h]
 -m <mbox> : mailbox file to parse
 -q <rt-queue id> : numeric ID for the queue where you want to load the mailbox
 -f : force, get rid of the interactive notices
 -v : verbose
 -h : this message
 
 }
 
 die "can't open mailbox $opts{'m'} (option -m)" unless (-r $opts{'m'});
 die "need a queue-id (option -q)" unless ($opts{'q'});
 # check if this is a valid queue
 my $queue = RT::Queue->new( $RT::SystemUser );
 $queue->Load( $opts{'q'} ); #this loads a queue by Id
 die "'$opts{'q'}' is not a valid queue id (option -q)" unless ($queue->Id);
 
 my $mgr = Mail::Box::Manager->new();
 
 
 my $folder = $mgr->open(
    $opts{'m'}
 );
 
 my $threads = $mgr->threads($folder);
 foreach my $thread ($threads->all() ) {
    if ($opts{'v'}) {
        print "**new thread**\n";
        print $thread->threadToString();
    }
    my @msgs = $thread->threadMessages;
    my $first = shift @msgs;
    my $ticket = process_first_msg($first);
    foreach my $rest ( @msgs ) {
        process_rest_msg($rest,$ticket);
    }
 }
 
 sub process_first_msg {
    my ($msg) = @_;
    if ($opts{'v'}) {
        print "\n**first-msg**\n". $msg->decoded ."\n****\n";
    }
    if ($opts{'v'} || !$opts{'f'}) {
        print "\n**email-addrs**\n". join("\n", map {$_->format} $msg->to, $msg->cc,$msg->from,$msg->sender);
        print "\n";
    }
    if (! $opts{'f'}) {
        print "\n**subject**\n". $msg->head->get('subject');
        print "\n";
        print "Are you sure to process this msg? Enter 'y' to verify, other to cancel\n";
        my $yes = <STDIN>;
        chomp($yes);
        return undef unless ($yes eq 'y');
    }
    my $Ticket = new RT::Ticket( $RT::SystemUser );
    my ( $ticket_id, $Transaction, $ErrStr ) = $Ticket->Create(
        Queue     => $queue->Id,
        Subject   => $msg->head->get('Subject'),
        Requestor => [ map {$_->format} $msg->from ],
        Cc        => [ map {$_->format} $msg->cc ],
        MIMEObj   => mailbox_to_rt($msg),
    );
    return $Ticket;
 }
 sub process_rest_msg {
    my ($msg,$ticket) = @_;
    if ($opts{'v'}) {
        print "\n**follow-up**\n". $msg->decoded ."\n****\n";
    }
    if ($opts{'v'} || !$opts{'f'}) {
        print "\n**email-addrs**\n". join("\n", map {$_->format} $msg->to, $msg->cc,$msg->from,$msg->sender);
        print "\n";
    }
    if (! $opts{'f'}) {
        print "\n**subject**\n". $msg->head->get('subject');
        print "\n";
        print "Are you sure to process this msg? Enter 'y' to verify, other to cancel\n";
        my $yes = <STDIN>;
        chomp($yes);
        return undef unless ($yes eq 'y');
    }
    my ($status,$retmsg) = $ticket->Correspond(
        CommitScrips => 0, #saw this in source code
        MIMEObj => mailbox_to_rt($msg),
    );
    print "Status: $status\n";
    print "Retmsg: $retmsg\n";
 }
 sub mailbox_to_rt {
    my ($msg) = @_;
    my $parser = RT::EmailParser->new();
    $parser->SmartParseMIMEEntityFromScalar( Message => $msg->string );
    return $parser->Entity();
 }

When used with HideGlobalScrips, I would get errors from this script (crit: Can't locate RT/QueueDeactivatedScrip.pm). The fix in my case was to add local/lib.

--- mbox2rt.pl  2005/08/15 15:15:13     1.1
+++ mbox2rt.pl  2005/08/15 15:16:05
@@ -6,7 +6,7 @@
 use Mail::Box::Manager;

 #TODO change this to your local RT lib
-use lib qw(/usr/local/rt34/lib);
+use lib qw(/usr/local/rt34/lib /usr/local/rt34/local/lib);
 use RT;

 RT::LoadConfig();

When using Ubuntu, you'll have to update the path. Below is what i've used to get it to work:

use lib ("/usr/share/request-tracker3.4/lib", "/usr/local/share/request-tracker3.4/lib");

Somehow the subject of the mail is not imported properly. For example, it results in this in RT after importation : =?iso-8859-1?q?Qu=E9bec_dans_l=27intranet?= This could be solved using the MIME::WordDecoder.