Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I run a mail server on which I have courier imap and pop3 running. Recently I moved some local messages from my machine (previously downloaded with pop3) onto the server so I could use imap. I used Mail.app on Mac OS X 10.5.8 to do this.

This resulted in a series of files on the mail server that look like this:

1324697191.M91227P15574V000000000000CA00I0004B07D_556.hostname,S=5622:2,S
1324697192.M322096P15574V000000000000CA00I0004B07F_557.hostname,S=225691:2,RS
1324697196.M144018P15574V000000000000CA00I0004B081_558.hostname,S=7702:2,RS
1324697197.M715598P15574V000000000000CA00I0004B083_559.hostname,S=15741:2,S
1324697199.M327587P15574V000000000000CA00I0004B085_560.hostname,S=8744:2,RS

The received times of these messages, in the same order as listed above, are:

01/15/2010
01/09/2009
07/13/2010
02/21/2010
05/06/2010

Now this isn't a problem with desktop mail clients -- they simply fetch all the messages, sort them, and everything is fine. Several google searches on this subject yielded threads where people were trying to get their messages in the correct order and the suggested remedy was "sort them on the client side."

Unfortunately, on iOS 5.0.1, the mail application assumes the order of the messages it gets from the imap server is already sorted by date. Due to the messages in this example having a filename that doesn't match their receive timestamp, but instead their reupload timestamp, this means that messages appear in the wrong order on an iOS device. To fix this, I have to load ALL of the mail by tapping the "Load More Messages" button a bunch of times.

I would like to simply be able to rebuild these message files such that the timestamp in the filename (which looks to be the first set of digits before the period) matches the receive timestamp. They would then be sorted in the right order for when an iOS device tries to load them. I don't know enough about how courier organizes messages -- can I simply write a script that replaces the first set of digits in the filename with the unix timestamp of the message receive time?

Thanks!

share|improve this question
    
Yes, you can. No problem. –  mailq Dec 24 '11 at 18:31

1 Answer 1

Thanks @mailq. It turns out that in addition to timestamp being at the beginning of the message filename, courier also looks at the modification timestamp of the file itself. I had to set that to the received timestamp as well.

Here's a script that will, given a bunch of messages, copy them to an output directory after rewriting the filename and the modification time to contain the receive timestamp.

#!/usr/bin/env perl

use Email::Simple;
use Date::Parse;
use Getopt::Long;
use File::Path qw(make_path);
use File::Copy qw(copy);
use File::stat;

my $outfolder = "";

$result = GetOptions("output-dir=s" => \$outfolder);

# create directories if needed
if (length($outfolder) > 0) {
    make_path($outfolder);
}

foreach my $file (@ARGV) {
    my $text = "";

    # read file as one string
    {
        local $/=undef;
        open FILE, "$file" or die "Couldn't open file: $!";
        binmode FILE;
        $text = <FILE>;
        close FILE;
    }

    # use Email::Simple to parse the Received header
    my $email = Email::Simple->new($text);
    my @received = $email->header("Received");

    # Find the latest receive time
    my $latestTime = 0;
    my $latestTimeStr = "";
    foreach my $r (@received) {
        if ($r =~ /[^;]*;(.*)$/) {
            my $time = str2time($1);

            if ($time > $latestTime) {
                $latestTime = $time;
                $latestTimeStr = $1;
            }
        }
    }

    # if this is a sent message, it doesn't have a received header. Use the
    # Date header instead.
    if ($latestTime == 0) {
        my $date = $email->header("Date");
        my $time = str2time($date);
        if ($time > $latestTime) {
            $latestTime = $time;
            $latestTimeStr = $date;
        }
    }

    # If we found one, rename or tell about the rename
    if ($latestTime != 0) {
        if ($file =~ /([0-9]*)(\..*$)/) {
            my $newfilename = $latestTime . $2;

            if (length($outfolder) == 0) {
                print "Would Copy $file ($latestTimeStr) -> \n             ";
                print "$newfilename\n";
            } else {
                print "Copied $file ($latestTimeStr) -> \n             ";
                print "$outfolder/$newfilename\n";

                # use the latest received timestamp as the atime and mtime
                copy($file, "$outfolder/$newfilename");
                utime($latestTime, $latestTime, "$outfolder/$newfilename");
            }
        }
    } else {
        print "Couldn't find receive time for " . $file . "\n";
    }
}

Use the script like this:

perl rename.pl cur/*

When you're convinced it will do the right thing:

perl rename.pl cur/* --output-dir cur_renamed

Then you'll just need to swap cur_renamed with cur, delete your courierimapuiddb file, and potentially restart your email clients. For my iOS device, I had to remove the mail account, then resync with iTunes to get it to properly clear the cache.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.