Redeliver messages from MBOX file

On occasion I encounter a situation where, due to a configuration issue, mail was received on a server and stored in the default MBOX format instead of being delivered to a user account on a real mail server.

the following script will read an mbox file and redeliver them to the original recipient specified in the message or, if specified, a global recipient.

#!/usr/bin/perl
#
# Usage:
#         redeliver_mbox.pl <mboxfile> [<global TO: address>]
#
#         The global TO: address is optional, setting this will cause all
#         messages to be delivered to that address instead of the TO:
#         address definined in the message.
# Examples:
#         To deliver all messages to me@example.com:
#         #> redeliver_mbox.pl mbox.txt me@example.com
#         To deliver all messages to the recipients listed in the message itself
#         #> redeliver_mbox.pl mbox.txt
my $sendmail='/usr/sbin/sendmail';
my $file = shift || die "need file\n";
my $gto  = shift; # global to.  if present, override other per-email decision
my $msg  = '';
my $to   = '';
my $from = '';
 
open(I, "<$file") || die "Can't open $file\n";
while (<I>) {
  if (/^From /) {
    print "From found\n";
    if ($msg) {
      if ($to && $from) {
        do_mail($from, $to, $msg);
      } else {
        print STDERR "have a message but no recipients\n";
      }
    } else {
      print STDERR "saw From: without message\n";
    }
    $msg  = '';
    $from = '';
    $to   = '';
  } elsif (/^Return-[pP]ath:\s*<(.*)>$/) {
    $from = $1;
        #print "from=$from\n";
  } elsif (/^To:\s*(.*)$/i) {
    $to = $1;
        #print "to=$to\n";
  } elsif (/^Date:\s*/) {
    ; # just ignore
  } else {
    $msg .= $_;
  }
}
close(I);
 
if ($msg && $to && $from) {
  do_mail($from, $to, $msg);
}
 
sub do_mail {
  my $f = shift;
  my $t = shift;
  my $m = shift;
  $t = $gto if ($gto);
 
  print "$f -> $t\n";
  print "MAIL FROM:<$f>\nRCPT TO:<$t>\nDATA\n$m\n.\n";
  open(P, "|$sendmail -f $f $t") || warn "can't open sendmail: $!\n";
  print P $m, "\n.\n";
  close(P);
}

Leave a Reply