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;
    
    <h1>TODO change this to your local RT lib</h1>
    
    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 &lt;&lt;"";
    Usage: $0 -m &lt;mailbox-file&gt; -q &lt;rt-queue-id&gt; [-f] [-v] [-h]
    -m &lt;mbox&gt; : mailbox file to parse
    -q &lt;rt-queue id&gt; : 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'});
    
    <h1>check if this is a valid queue</h1>
    
    my $queue = RT::Queue-&gt;new( $RT::SystemUser );
    $queue-&gt;Load( $opts{'q'} ); #this loads a queue by Id
    die "'$opts{'q'}' is not a valid queue id (option -q)" unless ($queue-&gt;Id);
    
    my $mgr = Mail::Box::Manager-&gt;new();
    
    my $folder = $mgr-&gt;open(
    $opts{'m'}
    );
    
    my $threads = $mgr-&gt;threads($folder);
    foreach my $thread ($threads-&gt;all() ) {
    if ($opts{'v'}) {
        print "<strong>new thread</strong>\n";
        print $thread-&gt;threadToString();
    }
    my @msgs = $thread-&gt;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<strong>first-msg</strong>\n". $msg-&gt;decoded ."\n****\n";
    }
    if ($opts{'v'} || !$opts{'f'}) {
        print "\n<strong>email-addrs</strong>\n". join("\n", map {$<em>-&gt;format} $msg-&gt;to, $msg-&gt;cc,$msg-&gt;from,$msg-&gt;sender);
        print "\n";
    }
    if (! $opts{'f'}) {
        print "\n<strong>subject</strong>\n". $msg-&gt;head-&gt;get('subject');
        print "\n";
        print "Are you sure to process this msg? Enter 'y' to verify, other to cancel\n";
        my $yes = &lt;STDIN&gt;;
        chomp($yes);
        return undef unless ($yes eq 'y');
    }
    my $Ticket = new RT::Ticket( $RT::SystemUser );
    my ( $ticket_id, $Transaction, $ErrStr ) = $Ticket-&gt;Create(
        Queue     =&gt; $queue-&gt;Id,
        Subject   =&gt; $msg-&gt;head-&gt;get('Subject'),
        Requestor =&gt; [ map {$</em>-&gt;format} $msg-&gt;from ],
        Cc        =&gt; [ map {$<em>-&gt;format} $msg-&gt;cc ],
        MIMEObj   =&gt; mailbox_to_rt($msg),
    );
    return $Ticket;
    }
    sub process_rest_msg {
    my ($msg,$ticket) = @</em>;
    if ($opts{'v'}) {
        print "\n<strong>follow-up</strong>\n". $msg-&gt;decoded ."\n****\n";
    }
    if ($opts{'v'} || !$opts{'f'}) {
        print "\n<strong>email-addrs</strong>\n". join("\n", map {$<em>-&gt;format} $msg-&gt;to, $msg-&gt;cc,$msg-&gt;from,$msg-&gt;sender);
        print "\n";
    }
    if (! $opts{'f'}) {
        print "\n<strong>subject</strong>\n". $msg-&gt;head-&gt;get('subject');
        print "\n";
        print "Are you sure to process this msg? Enter 'y' to verify, other to cancel\n";
        my $yes = &lt;STDIN&gt;;
        chomp($yes);
        return undef unless ($yes eq 'y');
    }
    my ($status,$retmsg) = $ticket-&gt;Correspond(
        CommitScrips =&gt; 0, #saw this in source code
        MIMEObj =&gt; mailbox_to_rt($msg),
    );
    print "Status: $status\n";
    print "Retmsg: $retmsg\n";
    }
    sub mailbox_to_rt {
    my ($msg) = @</em>;
    my $parser = RT::EmailParser-&gt;new();
    $parser-&gt;SmartParseMIMEEntityFromScalar( Message =&gt; $msg-&gt;string );
    return $parser-&gt;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;
  1. 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.