MacOSXのRubyでメールをPOPダウンロードしてPostgreSQLデータベースに保存する

あるメールアドレスで受信したメールを、POPでダウンロードしてパソコン内のPostgreSQLデータベースに保存する仕組みがほしかったので、Rubyを使って実装してみた。

PostgreSQLデータベースに保存するために、ruby-pgというライブラリを、また、タイムスタンプとかヘッダーとかを取り出すために、TMailというライブラリを、それぞれインストールした。

動作環境

動作確認した環境: MacOSX 10.6.8 + Ruby 1.8.7Macに最初から入っていた) + PostgreSQL 8.4.10
メールアカウントはGmailを使用。

PostgreSQLは/usr/local/pgsqlにソースからビルドしてインストール済み(ただconfigureとmakeしただけ。標準的な構成のはず)。
また、以下のような定義のテーブルmailboxを、文字コードUTF8のデータベースdb_mailbox内に用意した。

CREATE TABLE mailbox
(
id serial NOT NULL,
dt timestamp with time zone,
subject character varying,
body text,
CONSTRAINT mailbox_pkey PRIMARY KEY (id )
)
WITH (
OIDS=FALSE
);
ALTER TABLE mailbox
OWNER TO postgres;

ruby-pgのインストール

gemというコマンドを使用して導入する。コマンドラインから以下を実行:

$ sudo gem install pg -- --with-pg-config=/usr/local/pgsql/bin/pg_config

Password:
Building native extensions. This could take a while...
ERROR: Error installing pg:
ERROR: Failed to build gem native extension.

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb --with-pg-config=/usr/local/pgsql/bin/pg_config
Using config values from /usr/local/pgsql/bin/pg_config
checking for libpq-fe.h... yes
checking for libpq/libpq-fs.h... yes
checking for pg_config_manual.h... yes
checking for PQconnectdb() in -lpq... no
checking for PQconnectdb() in -llibpq... no
checking for PQconnectdb() in -lms/libpq... no
Can't find the PostgreSQL client library (libpq)
  :
  :
Gem files will remain installed in /Library/Ruby/Gems/1.8/gems/pg-0.13.2 for inspection.
Results logged to /Library/Ruby/Gems/1.8/gems/pg-0.13.2/ext/gem_make.out

失敗する。
いろいろ調べてみたところ、Rubyとは違うけどHDBC-postgresqlという環境で、PostgreSQLのアーキテクチャーがユニバーサルバイナリでないため導入に苦労したらしい、という情報があった。
自分はユニバーサルバイナリのことがあまりよくわかってないのだが、とにかくバイナリのアーキテクチャーの問題でPostgreSQLとの連携がうまくいかないのかもしれないと思い、ここを参考にfileコマンドでアーキテクチャーを確認してみた。

$ file /usr/local/pgsql/bin/postgres
/usr/local/pgsql/bin/postgres: Mach-O 64-bit executable x86_64

自分の場合はSnow Leopardの環境でビルドしていたので、PostgreSQLバイナリのアーキテクチャーはx86_64になっていた。
そのため、これに合わせてruby-pgも作る必要があったようだ。
以下のようにx86_64を指定して再度実行。

$ sudo env ARCHFLAGS='-arch x86_64' gem install pg -- --with-pg-config=/usr/local/pgsql/bin/pg_config
Password:
Building native extensions. This could take a while...
Successfully installed pg-0.13.2
1 gem installed
Installing ri documentation for pg-0.13.2...

Enclosing class/module 'rb_mPG' for class Connection not known

Enclosing class/module 'rb_mPG' for class Result not known
Installing RDoc documentation for pg-0.13.2...

Enclosing class/module 'rb_mPG' for class Connection not known

Enclosing class/module 'rb_mPG' for class Result not known
$

導入できた。

TMailのインストール

最初Rubyの標準機能で受信したメールを処理できないかと思ったが、試行錯誤した範囲ではできなかった。
ここの記事からTMailの存在を知り導入した。

ruby-pgと同様にgemで導入する。コマンドラインから以下を実行:

$ sudo gem install tmail
Password:
Building native extensions. This could take a while...
Successfully installed tmail-1.2.7.1
1 gem installed
Installing ri documentation for tmail-1.2.7.1...
Installing RDoc documentation for tmail-1.2.7.1...

Rubyスクリプト作成

実はPerlRubyのどっちを使うか迷ったのだが、NetBeansデバッグが出来ることからRubyを選んだ。
Windows版のNetBeans7ではRubyデバッグは出来なくなっているようだが、MacのNetBeans7では現時点で出来る)

以下のスクリプトを作成。こことかこことかこことかこことかここを参考にさせて頂きました。感謝。

require 'rubygems'
require 'net/pop'
require 'tmail'
require 'kconv'
require 'pg'

pop = Net::POP3.new('pop.gmail.com', 995)
pop.enable_ssl(OpenSSL::SSL::VERIFY_NONE)
pop.start('YourAccount, 'YourPassword')

db = PG.connect( :dbname => 'db_mailbox', :user => 'postgres')

if pop.mails.empty?
$stderr.puts 'no mail.'
else
pop.mails.each_with_index do |m, idx|
the_mail = TMail::Mail.parse(m.pop)
db.exec "INSERT INTO mailbox ( dt, subject, body ) VALUES ($1,$2,$3);", [the_mail.date, the_mail.subject.toutf8, the_mail.body.toutf8]
m.delete
end
$stderr.puts "#{pop.mails.size} mails popped."
end

pop.finish

POPダウンロードと文字コードの変換は、標準で入っていたライブラリで対応できた。

実行結果

以上の環境構築とスクリプトでメールをPostgreSQLデータベースに保存する仕組みが実現できた。

以下はテスト用のメールをGmailで見たところ。

スクリプトを実行すると、POPでダウンロードしてPostgreSQLのデータベースに保存できた。
以下は保存できたメールデータをpgadminで見たところ。