Jan
17th
Thu
17th
Import your IMAP mail to GMail, the easy way
found somewhere on the beautiful internet…
#!/usr/bin/env ruby
require 'net/imap'
require 'timeout'
# Source server connection info.
SOURCE_HOST = "current.mailhost.com"
SOURCE_PORT = 143
SOURCE_SSL = false
SOURCE_USER = "username"
SOURCE_PASS = "pass"
# Destination server connection info.
DEST_HOST = "imap.gmail.com"
DEST_PORT = 993
DEST_SSL = true
DEST_USER = "username@gmail.com"
DEST_PASS = "pass"
UID_BLOCK_SIZE = 10 # max number of messages to select at once
#messages with known issues.
blacklist = []
# Mapping of @source folders to @destination folders. The key is the name of the
# folder on the @source server, the value is the name on the @destination server.
# Any folder not specified here will be ignored. If a @destination folder does
# not exist, it will be created.
FOLDERS = {
# some examples:
# 'INBOX.@archive.2003' => '2003',
# 'INBOX.@archive.2004' => '2004',
# 'INBOX.@archive.2006' => '2006',
# 'INBOX.@archive.2007' => '2007',
# 'INBOX.@archive.Sent-Archive' => '[Import].Sent Mail'
'INBOX' => 'INBOX',
'INBOX.Sent' => 'Sent Mail'
}
# Utility methods.
def dd(message)
puts "[#{DEST_HOST}] #{message}"
end
def ds(message)
puts "[#{SOURCE_HOST}] #{message}"
end
def uid_fetch_block(server, uids, *args)
pos = 0
while pos e
ds "error: select failed: #{e}"
next
end
# Open (or create) @destination folder in read-write mode.
begin
dd "selecting folder ‘#{dest_folder}’..."
@dest.select(dest_folder)
rescue => e
begin
dd "folder not found; creating…"
@dest.create(dest_folder)
@dest.select(dest_folder)
rescue => ee
dd "error: could not create folder: #{e}"
next
end
end
# Build a lookup hash of all message ids present in the @destination folder.
dest_info = {}
dd "analyzing existing messages"
uids = @dest.uid_search(['ALL'])
dd "found #{uids.length} messages"
if uids.length > 0
uid_fetch_block(@dest, uids, ['ENVELOPE']) do |data|
dest_info[data.attr['ENVELOPE'].message_id] = true
end
end
# Loop through all messages in the @source folder.
uids = @source.uid_search(['ALL'])
ds "found #{uids.length} messages"
if uids.length > 0
uid_fetch_block(@source, uids, ['ENVELOPE']) do |data|
mid = data.attr['ENVELOPE'].message_id
# If this message is already in the @destination folder, skip it.
next if dest_info[mid]
#if this message has caused a hang before, skip it
next if blacklist.include?(mid)
# Download the full message body from the @source folder.
print mid # start with mid, then add d when downloaded, s when stored
msg = @source.uid_fetch(data.attr['UID'], ['RFC822', 'FLAGS','INTERNALDATE']).first
print "d" #downloaded
# Append the message to the @destination folder, preserving flags and
# internal timestamp.
proceed = false
begin
status = Timeout::timeout(15) {
@dest.append(dest_folder, msg.attr['RFC822'], msg.attr['FLAGS'], msg.attr['INTERNALDATE'])
}
proceed = true
rescue Net::IMAP::BadResponseError => bre
puts "Message Failed: #{bre.message}, skipping ";
blacklist.push(mid)
proceed = true
rescue Net::IMAP::NoResponseError => e
puts "Got exception: #{e.message}. Retrying…"
sleep 1
end until proceed
print "s " #stored
$stdout.flush
end # message store begin/rescue
end #messages in folder loop
rescue Timeout::Error => idle
puts "Timeout… adding #{mid} to blacklist"
blacklist.push(mid)
puts "loging out.."
@source.logout
puts "disconnecting.."
@source.disconnect
# doesnt work if the connection has already hung @dest.disconnect
setup_connections
redo
end # timeout begin/rescue
@source.close
@dest.close
end #folders loop
unless blacklist.empty?
puts "#{blacklist.length} Problematic Messages were skipped:"
blacklist.each { |mid| puts mid }
end
puts "done"
