RubyでGmailからIMAP経由で未読メールを取得する

twitterのフォロー通知メールとか、Amazonの発送通知メールとか、そういうメールを受け取ったらその内容に応じていろいろ処理したい時ってありますよね。
でもまあ、今時個人でメールサーバ立てるのなんて流行らないですし、自由にprocmailを仕込むわけにもいかないですよね。というわけでGmailIMAPを使いましょう。
rubyで書くとこんな感じ。

require 'rubygems'
require 'net/imap'
require 'kconv'
require 'pit'
require 'logger'

class ImapFetcher

  def initialize(pit_name)
    @pit = Pit.get(
      pit_name,
      :require=>{
        'host'=>'imap.gmail.com',
        'port'=>993,
        'use_ssl'=>'true',
        'login'=>'',
        'password'=>''
      }
    )
  end

  def logger
    unless @logger
      @logger = Logger.new(STDOUT)
      @logger.level = Logger::DEBUG
    end
    @logger
  end

  def logger=(logger)
    @logger = logger
  end

  def fetch(filter)
    mails = []
    begin
      # GmailIMAPで接続、ログインする
      @imap = Net::IMAP.new( @pit['host'], @pit['port'].to_i, @pit['use_ssl']=='true' )
      logger.debug 'IMAP.new'
      @imap.login( @pit['login'], @pit['password'] ) # ID、パスワード
      logger.debug "IMAP LOGIN #{@pit['login'].inspect}"

      # 受信箱を開く
      @imap.select( 'INBOX' )
      logger.debug 'IMAP SELECT INBOX'

      # メールを開く
      logger.debug "IMAP SEARCH #{filter.inspect}"
      @imap.search( filter ).each do | msg_id |
        logger.debug "FOUND msg_id:#{msg_id.inspect}"

        # 本文を取得する
        fetch_attr = '(UID RFC822.SIZE ENVELOPE BODY[HEADER] BODY[TEXT])'
        msg = @imap.fetch( msg_id, fetch_attr ).first
        logger.debug "IMAP FETCH #{msg_id.inspect} #{fetch_attr.inspect}"
        fetched_mail = {
          :body => msg.attr['BODY[TEXT]'].toutf8,
          :header => msg.attr['BODY[HEADER]'].toutf8
        }
        mails.push fetched_mail
        logger.debug "PUSHED #{fetched_mail[:header][/^Subject:.*$/]}"

        # 既読のフラグを立てる
        @imap.store( msg_id, '+FLAGS', [:Seen] )
        logger.debug "IMAP STORE #{msg_id.inspect} +FLAGS SEEN"
        #@imap.store( msg_id, '+FLAGS', [:Deleted] )
      end

      # フラグを反映
      @imap.expunge
      logger.debug "IMAP EXPUNGE"

    rescue Object=>e

      raise e # 例外処理

    ensure

      # 切断する
      @imap.logout
      logger.debug "IMAP LOGOUT"

      #@imap.disconnect
      #logger.debug "IMAP DISCONNECT"

    end
    mails
  end
end

使い方

Pitがなければ

$ gem install pit

する。
そんで ruby からは

imap = ImapFetcher.new('imap_fetcher_test')
mails = imap.fetch(['FROM', 'hogehoge@example.com', 'UNSEEN'])
pp mails

こんな感じ。


mailsには「hogehoge@example.com」から送られてきた未読メールのheaderとbodyがハッシュの配列になって入る。
IMAP FETCH のフィルターとしてUNSEENを指定しているので、未読メールのみが取得される。
ここで取得したメールには既読フラグを書き込んでいるので次回以降は取得されない。


github(gist)にも上げた。
imap_fetcher.rb

参考文献