EY-Officeではある目的にレンタルサーバーのメールを使っています。通常はそのサーバーからメールはGMailに転送して使っています。最近どうも転送されないメールがあるようなので調査しようと、そのレンタルサーバーの提供するWebメールを開いたのですが数分待たされた後エラーが発生して読めませんでした。
レンタルサーバーの管理画面を見るとメールボックスの大きさが3.9Gbyteになっていました❗
メールは転送しているだけで削除してなかったので数年分のメールが溜まったままでした。😅
それではとMacにメールソフトをインストールしIMAPでアクセスしようとしましたが、やはりエラーが発生し読めませんでした。POP3でアクセスしましたが全メールを取得し始め、いつ終わるのか判らないので中断しました。😭
そうだコードを書こう!
そうだ!こういう時はIMAPやPOP3プロトコルを話すコードを書けば良いのだ〜 😁
こういうクラシカルなプロトコルにはRubyが良いのではと思い、まずはnet/popライブラリを見たのですがこのレベルでは面倒かなと思い、Railsでも使われているmail Gemsを試したところ、以下のコードで3.9Gbyteのメールボックスから最新のメールや最古のメールがアクセスできました!😊
require 'mail'
Mail.defaults do
retriever_method(:pop3, {
address: 'メール(POP3)サーバー',
port: 995,
user_name: 'メールアドレス',
password: 'POP3のパスワード',
authentication: :login,
enable_ssl: true
})
end
# 以下で最新のメールが10件が取得できます
m = Mail.find(what: :last, count: 10, order: :desc)
# 以下で最古のメールのメールが10件が取得できます
m = Mail.find(what: :first, count: 10, order: :asc)
# 以下で最古のメールのメールが10件が取得でき、削除できます
m = Mail.find(what: :first, count: 10, order: :asc, delete_after_find: true)
これで、今回必要な以下のプログラムが作れそうです
- 古いメールの削除
- 最近のメールの一覧
メール情報の表示
古いメールの削除は、上に書いたサンプルコードでほぼ完成ですが、最近のメールの一覧は日付、送信元アドレス、件名などを表示する必要があります。しかし、mail Gemsの取得したメール情報のMessageオブジェクトには多数のメソッドが用意されていて、先に上げた項目はm[0].date
, m[0].from
, m[0].subject
で簡単に取得できました。
しかし、たくさんのメールの一覧を表示してみると問題がおきました。件名(サブジェクト)が無い場合がありました、さらに文字コードの問題もあります。😅 Rubyはいろいろな日本語コードに対応していますが、おかしな文字コードがあると例外が発生してしまいます。
今回の一覧表示は以下のように落ち着きました。NKFは昔からプログラミングされてきた方にはおなじみだと思いますが、元のエンコーディングが判らなくても適度に変換できるので私は好きです。
def list(mails)
mails.each_with_index do |m, i|
date = m.date ? m.date.to_time.getlocal.strftime("%F %T") : ""
from = m.from ? NKF.nkf("-w", m.from.kind_of?(Array) ? m.from[0] : m.from) : ""
subject = m.subject ? NKF.nkf("-w", m.subject[0, 30]) : ""
puts "#{sprintf("%2d", i)}: #{date} #{from} #{subject}"
end
end
ちょっと色気を出したら地獄が
ここまで、安易にできたので一覧表示に少し手を入れて選択したメールの本文を表示する機能を追加してみたら大変でした。😅
mail Gemsには m[0].text_part.decoded
でデコードされた本文が取得できますが、メールによっては.text_part
では本文が取得できませんでした。
また、このアプリはターミナルベースのアプリなのでHTMLメールをどうしようか悩んだのですが、html2textというgemを発見したのでこれを使いHTMLメールもテキストで表示する事にしました。
メール本文の表示は以下のようなコードに落ち着きました(まだまだ完成度が低いです)。
if m[ix].text_part
puts m[ix].text_part.decoded
else
s = NKF.nkf('-w',m[ix].body.to_s)
puts s.index(/<html.*?>/i) ? Html2Text.convert(s) : s
end
メールは歴史が長く、いろいろな文字コード、Base64/Quoted-printableなどのエンコーディング、マルチパートなど色々なバリデーションがあり、完璧に表示するのは大変そうです。メールソフトを作っている方の苦労には頭が下がります。