TMailはメールを簡単に扱うためのクラスライブラリです。
ヘッダはひとつひとつがオブジェクトとして表現され、
ヘッダを「文字列」としてでなく(めんどくさい文法に一切関ることなく)
「オブジェクト」とそのプロパティとして読み書きをすることができます。
また、MIMEマルチパートにも対応しています。
読みこみ時はヘッダに従って本文を分割し、
書きこみ時には適当にバウンダリを設定して再構成します。
一方で、TMailはメール本文の内容には一切関与しません。 文字コードも勝手には変換しませんし、行末コードも変えません。 Base64のデコードもしません。それはライブラリの利用者側で content-* ヘッダあたりを見て判断する必要があります。
簡単に、TMailライブラリを構成するクラス間の関係について書きます。
中心は TMail::Mail クラス(以下、Mail と略)です。 ひとつのメールがひとつのオブジェクトとして表現され、 (たぶんたくさんの)ヘッダフィールドと本文を含んでいます。
「ヘッダフィールド」とはようするに To: や From: のことです。ひとつの
ヘッダフィールドがひとつの HeaderField オブジェクトになります。
ヘッダフィールドオブジェクトは Mail の中に 'to' => Toヘッダフィールド
のようなハッシュとして格納されていて、Mail#[] や Mail#fetch でとりだせます。
ちなみに、mail['From'] も mail['FrOm'] も mail['FROM'] も同じヘッダです。
ヘッダはいろいろな種類があるので、それに対応するクラスもいろいろ用意されています。
たとえばTo:ヘッダはMaddrHクラスで表現され、Subject:はStringHクラスで表現されます。
to_s body inspect のように共通するメソッドもありますが、そのクラスに独自のメソッドも
たくさんあります。
Toヘッダならaddrsというメソッドがあります。これはそのヘッダで記載されている
アドレスの配列を返すメソッドで、 mail['to'].addrs.each {|adr| ... } の
ようにすればToのアドレス全てに対するくりかえしが行なえるわけです。
また、外界とのアクセスの抽象化のためにローダとポートがあります。 ローダはメールボックスの抽象表現で、ポートはファイルの抽象表現です。
本文は body で文字列として参照でき、body_port でポートとして参照できます。 MIME マルチパートメールでは、ひとつのパートがひとつの Mail として表現され、 その配列が Mail#parts メソッドで得られます。
実際に(少しは)使える例としてサンプルの fromcheck.rb を見てみます。 このスクリプトは、Mh のメールボックスの中にあるメールを調べて、 メールをくれた人を数の多い順に表示するスクリプトです。
require 'tmail/tmail' unless ARGV[0] then puts "usage: fromcheck.rbMhLoader.new からが TMail に独自なコードです。 MhLoader は Mh メールボックスを扱うクラスで、 他に Mbox と Maildir のローダがあります。" exit 1 end names = {} m = TMail::MhLoader.new( ARGV[0] ) m.each_mail do |port| tmail = TMail::Mail.new( port ) n = tmail.from_phrase(nil) || tmail.from if names.key? n then names[n] += 1 else names[n] = 1 end end names.to_a.sort {|a,b| b[1] <=> a[1] }.each do |name,i| puts "#{i} #{name}" end
そのローダのイテレータ each_mail からは、ポートを引数に渡されます。 TMail::Mail オブジェクトはこれを引数に生成します。
そうしたら、あとは好きにいじるだけです。from_phrase は From: ヘッダの"phrase"部分(friendly from などと呼ばれることもあります)を 取得するメソッドです。これは格納されていないこともあるので、ないときは メールアドレスを表示することにします。
Ruby や Perl の達人ならこのくらいは正規表現を使ったりして やっつけられるでしょうが、これほど簡単には書けないでしょう。 この単純さが TMail のいいところです。