RubyでIMAPのAPIを使ってメールをアーカイブする方法
概要
最近、Rubyを使ってメールサーバの操作をすることがあり、そこでメールをアーカイブする方法について色々調べました。 しかし、なかなかうまい方法が見つからなかったため、後学のために、どのようにしてメールのアーカイブしたのかを残しておきます。
環境
- Ruby 2.6
結論
まず、Rubyにはimapというライブラリがあり、これを使えばメールサーバにIMAPでアクセスして操作できます。そのため、メールの操作にはこれを使います。 また、メールのアーカイブは、INBOXという場所から、アーカイブ用の場所にメールを移すことなので、あらかじめ、アーカイブ用の場所を知っておく必要があります。
出来上がったものは次になります。 このソースコードでは、[email protected]というメールアドレスからのメールをアーカイブするというものになっています。
require 'net/imap'
require 'mail'
imap_host = ENV['IMAP_HOST']
imap_usessl = true
imap_port = 993
imap = Net::IMAP.new(imap_host, imap_port, imap_usessl)
imap_user = ENV['IMAP_USER']
imap_passwd = ENV['IMAP_PASS']
imap.login(imap_user, imap_passwd)
search_str = '[email protected]'
imap.select('INBOX') # 検索場所として受信ボックスを指定
ids = imap.search(['From', search_str]) # search_strに代入されているメールアドレスからの送信メールを取得
ids.each do |id|
mail = imap.fetch(id, %w[RFC822 UID]) # メールの内容の取得
m = Mail.new(mail.attr['RFC822'])
# 検索した内容に合ったものが取れているかチェック
next unless m.from.include? search_str
# メールのアーカイブ
imap.uid_copy(mail.attr['UID'], 'INBOX.Archive')
imap.uid_store(mail.attr['UID'], '+FLAGS', [:Deleted])
imap.expunge
end
imap.logout
imap.disconnect
メールサーバのアドレスやユーザ名やパスワードは環境変数から読み込むようにしています。
重要な部分としては、私の環境だけかもしれませんが、IMAPの検索でなぜか検索に一致しないようなメールが検索に引っかかりました。 そのため、mailというgemを別にインストールして、それを使ってメールのFromが本当に正しいのかをチェックしました。
また、メールのアーカイブはアーカイブ用の場所にメールを移動することですが、この移動はコピーして元のメールを消すということで実現しています。メールの指定は、メールにそれぞれ振られているUIDを使用しました。調べてみると、searchメソッドの戻り値でもできそうですが、私の環境ではうまくできなかったため、このような方法を取っています。メールの削除はDeletedというフラグを立てておき、それをexpungeというメソッドを使って実際の削除を行っています。
さいごに
メールの検索まではすんなりとできたのですが、実際に取得したメールが必ずしも検索しているものと一致するわけではなかったり、アーカイブの際にうまくいかなかったり、かなりハマるポイントがありました。