Created
August 12, 2009 06:09
-
-
Save hoanga/166350 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'net/imap' | |
require 'rubygems' | |
require 'tmail' | |
# Introduction: | |
# | |
# This small library is to archive emails from an imap server | |
# in an incremental fashion. None of the other tools (fetchmail, | |
# imapfilter, getmail) were able to do what I wanted which was: | |
# | |
# 1. Fetch a limited # of email messages from an imap inbox | |
# 2. Download and store into a Maildir backend | |
# | |
# Example usage that connects to Gmail and archives 100 messages into | |
# the Maildir directory '/home/myuser/maildir/new': | |
# | |
# ia = ImapArchive.new('myuser', 'mypassword') | |
# ia.archive_path = '/home/myuser/maildir/new' | |
# ia.process! | |
class ImapArchive | |
attr_accessor :username | |
attr_accessor :password | |
DEFAULT_OPTS = { | |
:server => 'imap.gmail.com', | |
:port => '993', | |
:mailbox => 'INBOX', | |
:max_count => 100, | |
:archive_type => 'Maildir', | |
:archive_path => '/tmp', | |
} | |
# Define accessor methods for all of the default_opts keys | |
DEFAULT_OPTS.keys.each do |opt| | |
define_method("#{opt}") { @config[opt] } | |
define_method("#{opt}=") { |param| @config[opt] = param } | |
end | |
# | |
# Returns an ImapArchive object, requiring a +username+ and +password+. | |
# Also can take an optional parameters hash to direct access to | |
# another server, port, inbox, or path to archive | |
# | |
# +opts+ arguments: | |
# | |
# :server => String (default : 'imap.gmail.com') | |
# :port => String (default : '993') | |
# :mailbox => String (default : 'INBOX') | |
# :max_count => Fixnum (default : 100) | |
# :archive_type => String (default : 'Maildir') | |
# :archive_path => String (default : '/tmp') | |
# | |
def initialize(username, password, opts = {}) | |
@username = username | |
@password = password | |
@config = DEFAULT_OPTS.merge(opts) | |
end | |
# Cleans up any messages that need to be deleted or processed via | |
# IMAP expunge command | |
def cleanup | |
@imap.expunge() | |
end | |
# Establish a connection to the imap server and sets the mailbox | |
def connect | |
@imap = Net::IMAP.new(@config[:server], @config[:port], true) | |
@imap.login(@username, @password) | |
@imap.select(@config[:mailbox]) | |
end | |
# Disconnect from the imap server | |
def disconnect | |
@imap.logout() | |
@imap.disconnect() | |
end | |
# Generates a unique-ish filename for storage into a Maildir directory | |
def get_uniq_filename | |
t = Time.now.to_i.to_s | |
h = `hostname`.chomp | |
pid = Process.pid.to_s | |
"#{t}.P#{pid}.#{h}" | |
end | |
# Does the heavy lifting of searching the mailbox for messages to | |
# process. Pulls the message down locally and stores into the | |
# +archive_path+ up to the +max_count+ configured | |
def pull | |
i = 0 | |
@imap.search(["NOT", "DELETED"]).each do |message_id| | |
mail = fetch_and_parse(message_id) | |
archive(mail) | |
i += 1 | |
@imap.store(message_id, "+FLAGS", [:Deleted]) # Delete | |
# Exit if we reach the max # of messages we want to process | |
break if i > @config[:max_count] | |
end | |
end | |
# A convenience method to connect, pull any outstanding messages, | |
# delete processed messages and disconnect from the server | |
def process! | |
connect | |
pull | |
cleanup | |
disconnect | |
end | |
private | |
def fetch_and_parse(message_id) | |
msg = @imap.fetch(message_id, 'RFC822') | |
TMail::Mail.parse(msg.first.attr['RFC822']) | |
end | |
def archive(mail) | |
# Archive it | |
fpath = @config[:archive_path] | |
fname = get_uniq_filename | |
File.open("#{fpath}/#{fname}", 'w') do |f| | |
f.puts(mail) | |
end | |
end | |
end | |
if __FILE__ == $0 | |
require 'yaml' | |
config = YAML.load_file('gmail.yml') | |
username = config[:username] | |
password = config[:password] | |
imap = ImapArchive.new(username, password, config) | |
imap.process! | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment