Skip to content

Instantly share code, notes, and snippets.

@entp
Created February 15, 2011 02:02
Show Gist options
  • Save entp/826969 to your computer and use it in GitHub Desktop.
Save entp/826969 to your computer and use it in GitHub Desktop.
Downloads all the messages in your imap mailbox and saves them as files.
require 'net/imap'
class ImapWrapper
attr_reader :imap
module Constants
RFC822 = 'RFC822'.freeze
IDATE = 'INTERNALDATE'.freeze
M_ID = "BODY[HEADER.FIELDS (MESSAGE-ID)]".freeze
SUBJECT = "BODY[HEADER.FIELDS (SUBJECT)]".freeze
TO = "BODY[HEADER.FIELDS (TO)]".freeze
BODY = "BODY[TEXT]".freeze
FROM = "BODY[HEADER.FIELDS (FROM)]".freeze
SIZE = "RFC822.SIZE".freeze
UID = "UID".freeze
FLAGS = "+FLAGS".freeze
def clean_message_id(s)
s.sub! /^[^<]+</, ''
s.sub! />.*$/, ''
s.strip!
s
end
end
include Constants
def initialize(user, pass, purge_messages = false, verbose = false)
@purge_messages = purge_messages
@verbose = verbose
@imap = Net::IMAP.new('imap.gmail.com', 993, true)
@imap.login(user, pass)
end
def verbose?
@verbose
end
def purge_messages?
@purge_messages
end
def each_message(mailbox, query, attributes, options = {}, &block)
each_uid(mailbox, query) do |all_uids|
while uids = paginated(all_uids, options)
fetch(uids, attributes).each do |data|
if block && data.attr
uid = data.attr[UID]
block.call(uid, data.attr)
end
end
end
end
end
def each_message_id(mailbox, query, &block)
each_message(mailbox, query, M_ID, :per_page => 30) do |uid, data|
id = data[M_ID]
id.sub! /^[^<]+</, ''
id.sub! />.*$/, ''
id.strip!
block.call(uid, id) if block
end
end
def fetch(uid, attributes)
if attributes.respond_to?(:join)
attributes = "(#{attributes * " "})"
end
@imap.uid_fetch(uid, attributes) || []
rescue
puts "Error fetching #{uid.inspect}"
puts $!.inspect
end
def copy_to(uid, mailbox)
@imap.uid_copy uid, mailbox
end
def move_to(uid, mailbox)
copy_to uid, mailbox
purge uid
end
def store(uid, attr, flags)
@imap.uid_store(uid, attr, flags)
end
def purge(uid)
puts "PURGING: #{uid.inspect}" if verbose?
store uid, FLAGS, [:Deleted]
end
def mailboxes
@imap.list('', '*').map { |m| m.name }
end
def close
puts "EXPUNGE!" if purge_messages?
@imap.expunge if purge_messages?
@imap.logout
end
def mailbox(name)
@imap.select(name)
end
private
# :limit => ONLY send this many back
# :per_page => return items in pages
def paginated(array, options = {})
page = []
page_size = options[:limit] || options[:per_page] || 10
page_size.times { page << array.shift }
page.compact!
if options[:limit] then array.clear end
page.empty? ? nil : page
end
def each_uid(mailbox_name, query, &block)
mailbox(mailbox_name)
uids = @imap.uid_search(query)
puts "#{uids.size} uid(s) found..." if verbose?
block.call(uids.dup) if block && uids.size > 0
uids
end
end
IMAP = { :user => "you@gmail.com", :pass => "yourpassword" }
namespace :imap do
wrapper = nil
task :connect do
dir = "#{File.dirname(__FILE__)}/../../../../"
require 'imap_wrapper'
include ImapWrapper::Constants
wrapper = ImapWrapper.new(IMAP[:user], IMAP[:pass], ENV['PURGE'], ENV['VERBOSE'])
mbox = ENV['MBOX'] || "INBOX"
dest = ENV['TO'] || "reprocessed"
FileUtils.mkdir_p(File.join(File.dirname(__FILE__), "queue"))
wrapper.each_message(mbox, "ALL", [M_ID, RFC822], :per_page => 100) do |uid, data|
raw = data[RFC822]
path = File.join("queue", "#{uid}.eml")
File.open(path, 'w') { |f| f << raw }
puts "Wrote #{path} (#{raw.size})"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment