かなり前になりますが、miyagawaさんがPlaggerの開発始めたときのプラグイン機構の話で例にあげていた qpsmtpd、ずっと気になっていたのですがやっとさわってみました。
これを使って、メールでルー語変換というのを作ってみました。 m@lou5.jpにメールを送ると、件名や本文がルー語変換されて戻ります。自分で楽しむなり、戻ってきたルー語メールを転送するなり、ご自由にお試しください。ルー語変換は携帯から使いたいという声が多かったのですが、これで携帯でもいけるかな、と。
携帯アドレスの場合絵文字を混ぜて返すとか、PCの場合HTMLメールで返したりとか、いろいろ夢はひろがりますが、それはまた時間取れたときやります。。
qpsmtpd
日本語の言及が少ないのでちょっと書いておくと、全部がプラグインでできたPerlによるSMTPサーバー。スパム対策に強いsmtpdとして普通に知られてるようですが、デーモンとして立ち上がっていてくれるので、Perl書きには mod_perl 的に使えるという代物です。この前のYAPC::Asiaで、VOX の自動返信メール部分でこれを使ってるって話していました。
自動返信メールだと、alias駆動みたいなのでもいいのですが、やはり毎回プロセスが立ち上がるというのはアクセス(送信)が集中したときのサーバーリソースが怖い。
インストール。ソースから入れる方法 もWikiに細かく書いてあるんですが、パッケージから。OS Fedoraなのですが、yumで見つからなかったので、RPM とその依存を解決するために必要なのをこことかから落っことしてきて rpm -i。すんなり入りました。
仕組みは、blosxomぽい。plugins/ ディレクトリにスクリプトの断片が置かれてて、config/plugins ファイルに、使うプラグインを1行1個で列挙。同じフックポイントにかかるプラグインは、そこに書かれた順で起動。プラグインによってもっと設定が必要な場合は、config/ 以下にプラグインと同じ名前でファイルを置き、そこに設定を書くことで使える。config/ 以下にはloglevelみたいな本体が使う設定ファイルも混じっている。
さっそくtelnet localhost 25で試してみる。実装がPerlなのとソースがきれいなので勉強になります。check_earlytalker プラグインとか面白いです。plugins/ ディレクトリのスクリプト断片は、Filter::EntryFullTextで .plなassetの呼ばれ方に似てる(Qpsmtpd::Pluginのcompile() 参照)。
qpsmtpdはやたらノリノリなMTAです。QUITのあとHave a wonderful day. とか言われて開発者のキャラが見えます。
実はQmailやpostfixを完全にリプレースするものかと思ってたのですが、そうじゃなくsmtpd部分のみを置き換えるものだということをここで知る(笑)。それ以外の、キューを配送するところとかは 何がしかのMTAが必要。もともとpostfixだったので、postfix/master.cfのsmtpdのところをコメントアウトして起動。Fedora(Redhat)の場合 /etc/init.d/qpsmtpd-forkserver が使う設定は ` /etc/sysconfig/qpsmtpd-forkserver` にありますが、そこのローカルホストしばりを外し終了。というわけで、今lou5.jp:25はqpsmtpdが受けています。
Pluggableなアプリの利点はいろいろですが、既存のプラグインの中からやりたいことと似ているものを探し、パクるとこから始められるという入りやすさもありますよね。今回は自動返信メールということになるので、PlaggerでいうPublishのようなフェーズである hook_queue にかかるモジュールを参考につくり始めました。
プラグインの書き方は簡単。この辺に使えるhookの一覧と受け取る引数、何を返すとどうなるかが。最初に書いたテストプラグイン。
sub hook_queue {
my ($self, $transaction) = @_;
$self->log(LOGINFO, "## sender:" . $transaction->sender->address);
$self->log(LOGINFO, "## from:" . $transaction->header->get('from') );
return (DECLINED, "pass to next plugin.");
}
これをplugins/hogeとして保存して、config/pluginsにhogeって書くと、ログにsenderとfromを出します。$transactionオブジェクトについては perldoc lib/Qpsmtpd/Transaction.pm
書いてると、処理部分をサーバーサイドのCatalystアプリのLou5::Siteと一緒に、Lou5::Mailにまとめたくなります。そんな人向けに? qpsmtpdはconfig/pluginsにplugins/ 以下のファイル名ではなく、Foo::Barみたいなモジュール名を書けます。
その場合Foo::Barが呼ばれるのですが、Lou5::Mailはシステムライブラリ領域には置いていないんでモジュールが見つからないエラーになります。taintモードで動いているqpsmtpdにPERL5LIBとかで勝手パスを渡すのはむずかしく、結局plugins/lou5_mailというファイルを用意して、
use lib '/home/tomi/Lou5/lib';
use Lou5::Mail;
と書き、Lou5::Mail側ではいろいろexportするという方法をとりました。レポジトリはこのへんです。config/pluginsは queue/postfix-queue の前に lou5_mail と入れてます。