Parsing IMAP folders using Ruby

Output from a ruby appOne of the advantages of running my own mail server for me and Kate to use is that I can create custom email address schemes to thwart the attempts of heinous spammers.

Without divulging our strategy (for fear—perhaps rather self-aggrandisingly—of immediately being swamped with a deluge of unwanted mail) , it means that Kate and I have a larger-than-normal number of incoming addresses to contend with. Some of these are single-use, so I can’t always remember every address I’ve used.

I’m still trying to decide how best to manage our emails when we’re in Uganda. The most likely solution will be to use my hosting at Joyent, maybe in conjunction with some pre-delivery spam scanning from Postini (now part of Google). Whatever the solution, it won’t involve using our home server running Postfix, so I thought it would be useful to see just how many addresses I’ve used in the last year or so.

I’m a bit of a Ruby fan, so I’ve written a quick script to go through a variable number of IMAP folders, looking for a ‘target domain’ (edjones.org in my case) in the ‘to’ address field. When it finds that address, it’ll store it, de-duplicate the resulting list and stick them in a sensibly-named folder.

I’ve used this on Dovecot IMAP, my server of choice. YMMV, as they say. Feel free to do whatever you like with this script.


require 'net/imap'
require 'logger'

log = Logger.new('log.txt')

#settings
server = "MY SERVER NAME"
user = "MY LOGIN"
password = "MY PASSWORD"
folders = ["folder_name_1","folder_name_2","etc"]
target_domain = "edjones.org"
since_date = "1-Jan-2007"

#login to the IMAP server
imap = Net::IMAP.new(server)
log.info("Logging in...")
imap.login(user, password)

#Iterate through each folder specified above
folders.each do |folder|
  log.info("selecting folder #{folder}...")
  imap.select(folder)

  #Create a new array to hold the addresses
  addresses = Array.new
  
  imap.search(["SINCE", since_date]).each do |msg_id|
    env = imap.fetch(msg_id, "ENVELOPE").first.attr["ENVELOPE"]
  
    # Iterate through each to address to find mine (the target domain)
    env.to.each do |to|
      if to.host.match(target_domain)
        log.info("Matched #{target_domain}, writing #{to.mailbox}@#{to.host}")
        addresses << to.mailbox + "@" + to.host
      end 
    end
  end

  #open a file to writing (calling it something sensible)
  out = File.open("#{folder.gsub(" ","_")}_uniques","w")
  
  #Weed out dupes
  addresses.uniq!
  #and stick the result into the file
  addresses.each { |a|
    out.puts a
  }
  #close the file
  out.close
end

#log out of the IMAP server
imap.logout
imap.disconnect

(Props to this Devdaily script for the initial idea)

Your comments on this article

Share your thoughts using the form below. I'd love to hear from you. Comments are hosted using Disqus.

(Alternatively, get in touch with me here)

Recently

Possibly Related

(Based on the tag(s) and programming)