Posts Tagged ‘IMAP’

IMAP Purge revisited

No Comments »

I noticed, looking at the logs this morning, that the previous script bombs if you delete a mail folder without removing it from your yaml configuration. So, here’s a new and (slightly) improved version

Along with handling the exception, it now creates and appends to a log file per month (instead of creating one each day which proved a bit “messy”).

#!/usr/bin/ruby
require 'net/imap'
require 'date'
require 'yaml'

Config = Struct.new(:imapServer, :userid, :password, :purgePeriods)

root = File.dirname($0) +File::SEPARATOR
t = Date.today
$stderr = $stdout = File.new(root+"cleanup_#{t.year}_#{t.month}.log",'a')
config = YAML.load_file(root+'mailClean.yaml')

imap = Net::IMAP.new(config.imapServer)
imap.login(config.userid,config.password)

puts "================n================"
puts "executing : #{Time.now}"
puts "================n================"
config.purgePeriods.each do |mailbox,days|
  pDate = Date.today - days
  delCount = 0
  puts "====(#{mailbox}:purge before #{pDate})===="
  begin
    imap.select(mailbox)
    msns = imap.search(['NOT','NEW'],'US-ASCII')
    threads = {}
    sl = msns.slice!(0..200)
    while (sl.length>1)
      sl = [sl] if sl.class == 'Fixnum'
      data = imap.fetch(sl,['ENVELOPE'])
      data.each do |d|
        env = d.attr['ENVELOPE']
        next unless env.date
        subject =  env.subject || ''
        threadSubject = subject.sub(/^Re:s*/i,'')
        dt = Date.parse(env.date)
        if threads[threadSubject]
          t = threads[threadSubject]
          t[:latest] = dt if dt > t[:latest]
          t[:msns] << d.seqno
        else
          threads[threadSubject] = {:latest => dt,:msns =>[d.seqno]}
        end
      end
      sl = msns.slice!(0..200)
    end
    threads.each do |key,val|
      if val[:latest] < pDate
        puts "#{key} == #{val[:latest]} #{val[:msns].inspect}n"
        delCount += val[:msns].length
        imap.store(val[:msns],'+FLAGS',[:Deleted])
      end
    end
    puts "deleted #{delCount} messagesn"
    imap.expunge
  rescue
    puts "Error Encountered!:#{$!}"
  end
end

imap.logout

Thread aware IMAP message purge

No Comments »

I subscribe to a number of mailing lists, and use .mac (mobile.me) IMAP for my email. I don’t like to delete everything immediately (so I can follow back through a thread if needed). So, I started looking for a way with mac mail, to have message threads cleaned up after a period of time. Of course, I’d like that period of time to vary by mailbox.

Naturally, this doesn’t seem to be possible with the native capabilities of mac mail, so I started looking into scripting something for mac mail. After a bit of looking around, this seemed less than productive, and it dawned on me that Ruby has an IMAP library. So I set about building the following script to take care of keeping my mailboxes managed.

The idea is that any message in a thread with a message in the last X days (configurable by mailbox) will be retained. All other messages are deleted.

The code is not particularly optimized, and may take some time, particularly on the initial execution if you have a lot of history built up. I’m open to suggestions for improvement, so fire away.

WARNING: This code is tested with the mobile.me IMAP server for my personal needs. If you want to use it, please feel free, but you may have to modify it for your particular IMAP server. I make no warranty, implied, inferred, suggested, specific, or otherwise that it will suit your purposes, that it will not delete every last email you’ve ever received, etc. (but hey, it works for me, and it might save you some time in a similar task)

“cleanMail.rb”:

#!/usr/bin/ruby
require 'net/imap'
require 'date'
require 'time'
require 'yaml'

Config = Struct.new(:imapServer, :userid, :password, :purgePeriods)    

root = File.dirname($0) +File::SEPARATOR
$stderr = $stdout = File.new(root+"cleanup_#{Date.today}.log",'a')
config = YAML.load_file(root+'mailClean.yaml')

imap = Net::IMAP.new(config.imapServer)
imap.login(config.userid,config.password)

puts "executing : #{Time.now}"
config.purgePeriods.each do |mailbox,days|
  pDate = Date.today - days
  delCount = 0
  puts "====(#{mailbox}:purge before #{pDate})===="
  imap.select(mailbox)
  msns = imap.search(['NOT','NEW'],'US-ASCII')
  threads = {}
  sl = msns.slice!(0..200)
  while (sl.length>1)
    sl = [sl] if sl.class == 'Fixnum'
    data = imap.fetch(sl,['ENVELOPE'])
    data.each do |d|
      env = d.attr['ENVELOPE']
      next unless env.date
      subject =  env.subject || ''
      threadSubject = subject.sub(/^Re:s*/i,'')
      dt = Date.parse(env.date)
      if threads[threadSubject]
        t = threads[threadSubject]
        t[:latest] = dt if dt > t[:latest]
        t[:msns] << d.seqno
      else
        threads[threadSubject] = {:latest => dt,:msns =>[d.seqno]}
      end
    end
    sl = msns.slice!(0..200)
  end
  threads.each do |key,val|
    if val[:latest] < pDate
      puts "#{key} == #{val[:latest]} #{val[:msns].inspect}n"
      delCount += val[:msns].length
      imap.store(val[:msns],'+FLAGS',[:Deleted])
    end
  end
  puts "deleted #{delCount} messagesn"
  imap.expunge
end

imap.logout

You’ll need to have a “mailClean.yaml” file similar to the following in the same directory as the cleanMail.rb file. Of course, you’ll need to supply your own IMAP server name, user id, and password. And, the example mailboxes are mine, so you’ll need to tailor to your mailbox structure (just leave out mailboxes that you don’t want the script to manage). in the purgePeriods, just enter each IMAP mailbox you want to manage and the number of days after which a thread should should expire.

--- !ruby/struct:Config
imapServer: <your imap server>
password: <your password>
userid: <your userid>
purgePeriods:
  Tech: 30
  Mac/iTunes: 30
  Humor/Jokeroo: 360
  Drafts: 360
  Deals: 30
  Junk: 30
  Programming/Ruby/Heroku: 60
  Mac/MacWorld: 90
  CNET: 30
  Programming/Ruby/Sripting Leopard: 90
  Programming/Ruby/IronRuby: 90
  Programming/ANTLR: 60
  Humor/Clean Laffs: 30
  Humor/Bizarre Video: 30
  Humans: 30
  Programming/Ruby/Ruby on Rails: 90
  Programming/GWT: 30
  Mac/Apple: 360
  Lockergnome: 30
  Programming/Ruby/Rb Appscript: 30
  Troop 169: 120
  Programming/Ruby/Ruby Quiz: 30
  Programming/Ruby/Ruby Core: 90


Edit translation
Machine translation (Google):
Loading...
Copy to editor
or Cancel