Skip to content

Instantly share code, notes, and snippets.

@growse
Created June 25, 2012 22:30
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save growse/2991832 to your computer and use it in GitHub Desktop.
Save growse/2991832 to your computer and use it in GitHub Desktop.
A way to incrementally upload a maildir to gmail's IMAP servers. Originally by Andreas Kammlott, with some changes
#!/usr/bin/perl
# by Andreas Kammlott, thanks to perl and its community
use IO::Socket::SSL;
use Data::Dumper;
use HTTP::Date qw(str2time);
use HTTP::Date qw(parse_date);
use Date::Format;
use Mail::IMAPClient;
use Mail::Box::Maildir;
use Mail::Message::Convert::MailInternet;
# Open imap connection, adjust values to your needs
my $imap = Mail::IMAPClient->new(
User => 'username',
Password => 'password',
Socket=>IO::Socket::SSL->new(Proto=>'tcp',
PeerAddr=>'imap.gmail.com',
PeerPort=>993)
) || die "Could not connect to IMAP server.\n";
# A maildir contains a subdir "cur"
foreach my $dir (`find ./ -type d -name cur|sort`) {
my $imdir = "Inbox"; # to store the path on the server (imap-directory)
my $fsdir = ""; # to store the path of the maildir (filesystem)
# Bring the path to an array, each directory needs to be handled
my @fspath = split(/\//, $dir);
# Replace the leading point and the tailing .directory to acquire
# the path, which has to be created in imap, the "cur" don't need
# to be stored
for (my $i = 1; $i < @fspath-1; $i++) {
$fsdir = "$fsdir$fspath[$i]/";
if ($fspath[$i] =~ /\..*\.directory/) {
$fspath[$i] =~ s/^\.(.+)\.directory$/$1/;
}
#$imdir = "$imdir$fspath[$i]/";
}
# Create the mdir object, this object contains all the messages from
# the filesystem's maildir
my $mdir = Mail::Box::Maildir->new(folder => $fsdir, access => 'rw')
or print "Failed to create mdir object from \"$fsdir\"\n";
# Process this directory only if it contains messages
if (!$mdir->messages() > 0) {
#print "Skipping... folder has been detected as empty.\n";
next;
}
#print Dumper($imap->xlist_folders or die "could not get folder $!");
#exit;
# Check for the folder on the server (imap) and create if necessary
if (!$imap->exists($imdir)) {
# Jump to next folder if creation of this one fails
if (!$imap->create($imdir)) {
print "ERROR: Could not create folder \"$imdir\".\n";
next;
}
}
# Now begin to push all messages
foreach my $msg ($mdir->messages()) {
if ($msg->label(seen) eq 0) {
my $subject = $msg->subject;
my $msgdate = $msg->head->get('Date');
my $msgid = $msg->messageId;
print $subject." - ".$msgid."\n";
# Required date as RFC2060 dd-Mon-yyyy hh:mm:ss +0000
# Provided format is Tue, 20 Jul 2004 09:55:16 +0200
my $time = str2time($msgdate);
(undef, undef, undef, undef, undef, undef, $tz) = parse_date($msgdate);
my $date = time2str("%d-%h-%Y %H:%M:%S %z",$time,$tz)
or print "problem with time: $time and tz: $tz\n";
# Create a converter object
my $conv = Mail::Message::Convert::MailInternet->new;
# Don't understand why the $conv->export($msg)->as_string() has to be called twice!
my $exp = $conv->export($msg)->as_string();
if (!$imap->append_string($imdir, $conv->export($msg)->as_string(), undef, $date)) {
print "Failed to append message!\n"
."ID:$msgid\n"
."SUBJECT:$subject\n"
."IMAPDIR:$imdir\n"
."MESSAGEDATE:$msgdate\n"
."IMPORTDATE:$date\n\n";
} else {
# Delete the message now that we've uploaded it.
$msg ->label(seen => 1)
}
}
}
}
$imap->close();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment