class ICFS::Email::Imap

Get email using IMAP

Public Class Methods

new(core, log, opts={}) click to toggle source

New instance

@param core [Email::Core] The core email processor @param log [Logger] The log @param opts [Hash] configuration options @option opts [String] :address The server address @option opts [Integer] :port The server port @option opts [Boolean] :enable_ssl Use SSL or not @option opts [String] :username The login username @option opts [String] :password The login password @option opts [String] :mailbox The mailbox to read @option opts [Array,String] :keys keys to pass to {::Net::IMAP#uid_search} @option opts [Integer] :idle_time Seconds to wait IDLE before polling @option opts [Integer] :reconnect Seconds after which we can reconnect

# File lib/icfs/email/imap.rb, line 42
def initialize(core, log, opts={})
  @core = core
  @log = log
  @cfg = {
    :port => 993,
    :enable_ssl => true,
    :keys => 'ALL',
    :idle_time => 60*5,
    :reconnect => 60*15,
  }.merge!(opts)
end

Public Instance Methods

fetch() click to toggle source

Fetch messages

# File lib/icfs/email/imap.rb, line 81
def fetch()

  # open & login
  imap = ::Net::IMAP.new(@cfg[:address], @cfg[:port],
      @cfg[:enable_ssl], nil, false)
  imap.login(@cfg[:username], @cfg[:password])
  @log.info('IMAP: open and login')

  # mailbox
  if @cfg[:mailbox]
    imap.select(::Net::IMAP.encode_utf7(@cfg[:mailbox]))
    @log.info('IMAP: mailbox selected: %s' % @cfg[:mailbox])
  else
    @log.error('IMAP: no mailbox specified')
    mbxs = imap.list('', '*')
    @log.info('IMAP: mailbox list: %s' % mbxs.map{|mb| mb.name }.join(', '))
    return
  end

  while true
    # fetch messages
    uids = imap.uid_search(@cfg[:keys])
    @log.debug('IMAP: %d messages found' % uids.size)
    uids.each do |uid|
      fd = imap.uid_fetch(uid, ['RFC822'])[0]
      @log.debug('IMAP: message fetched')
      msg = ::Mail.new(fd.attr['RFC822'])
      @core.receive(msg)
      if @cfg[:delete]
        imap.uid_store(uid, "+FLAGS", [:Deleted])
        @log.debug('IMAP: message deleted')
      end
    end
    if @cfg[:delete]
      imap.expunge
      @log.debug('IMAP: expunged')
    end

    # wait IDLE until new mail
    if @cfg[:idle_time]
      @log.debug('IMAP: starting IDLE')
      imap.idle(@cfg[:idle_time]) do |resp|
        if resp.is_a?(::Net::IMAP::UntaggedResponse) && resp.name == "EXISTS"
          @log.debug('IMAP: new mail, IDLE done')
          imap.idle_done
        end
      end
      @log.debug('IMAP: exited IDLE')

    # or we just run once
    else
      @log.debug('IMAP: fetch completed')
      break
    end
  end

ensure
  if defined?(imap) && imap && !imap.disconnected?
    imap.disconnect
    @log.info('IMAP: disconnected')
  end
end
reconnect() click to toggle source

Handles reconnects when dropped

# File lib/icfs/email/imap.rb, line 58
def reconnect()

  while true
    start = Time.now
    begin
      fetch()
    rescue EOFError
      if( (Time.now - start) > @cfg[:reconnect] )
        @log.info('IMAP: lost connection, reconnecting')
        next
      else
        @log.error('IMAP: disconnected under the reconnect limit')
        break
      end
    end
  end

end