James君!〜FetchMail機能

FetchMail コマンドで転送

さて、今度は fetchmail を使う、易しい連携プレーだ。まあ、これは fetchmail 自体が判っていればどうということもない。フツーに MTA に対して POP サーバを立ててやり、MTA から POP サーバにメールが流れるようにしてやっておけば、あとは cron ジョブかなんかに仕掛けておいた fetchmail が定期的に起動する、という当り前なやり方で十分機能する。

まあ、それでも fetchmail の設定例でも示すことにするか。

set logfile fetchmail.log
poll localhost
  protocol POP3
  user sug@mydomain.jp
  password hogehoge
#  keep   -- すでにあるものを削除する
  smtphost 127.0.0.1/1025
  smtpname sug@localhost

言うまでもなく、この fetchmailrc は

# ls -l /home/nadai/yemni-test/fetchmailrc
-rwx--x---    1 root     root          186  9月 24日  20:32 fetchmailrc*

みたいなパーミッションでないと、fetchmail に怒られる。

James の FetchMail 機能を使う

...まあ、これだけだと、わざわざこのページに書くまでもないようなことなんだが、実は面白いことに、James 自体にこの fetchmail 機能が入っているんである! しかし、ちょっとばかり問題もあるんで、それを指摘する。

実際、James を起動した時に、

$ bin/run.sh
Using PHOENIX_HOME:   /home/sug/public_html/soft/james/james-2.2.0
Using PHOENIX_TMPDIR: /home/sug/public_html/soft/james/james-2.2.0/temp
Using JAVA_HOME:      /usr/local/jdk1.5.0_04
Running Phoenix:

Phoenix 4.0.1

James 2.2.0
Remote Manager Service started plain:4555
POP3 Service started plain:1110
SMTP Service started plain:1025
NNTP Service started plain:1119
Fetch POP Disabled
FetchMail Disabled

というバナーが出る、というのはすでに実体験したものと思う。ここでのポイントは言うまでもなく「Fetch POP」と「FetchMail」である。James 自体のサブ機能として、やはり fetchmail 機能を持っているんだな。しかし、「Disabled」となっていることから判るように、これはデフォルトでは停止している。fetchmail 機能を有効にするには、james-2.2.0/apps/james/conf/james-fetchmail.xml を編集する必要がある。ちなみに Fetch POP の方は、fetchmail の旧バージョンみたいなもので、「それの互換動作」というノリであるものだから、こっちはまあどうでもいい。

実際のところ、James の設定ファイルは james-2.2.0/apps/james/SAR-INF/config.xml だ。どういう関係にあるのか?というと、

<?xml version="1.0"?>
<!DOCTYPE config [
<!ENTITY listserverConfig SYSTEM "../conf/james-listmanager.xml">
<!ENTITY listserverStores SYSTEM "../conf/james-liststores.xml">
<!ENTITY fetchmailConfig SYSTEM "../conf/james-fetchmail.xml">
]>

<config>
   <James>
      (略)
   </James>

   <!-- Fetch pop ブロック。POP3 サーバからメールを取り出して、自分の受け取り
        スプールに入れる。警告:<James>ブロック内の <servernames> セクションに
	注意して、フェッチしたメールがループしないようにするのは重要だ!
	このブロックはデフォルトでは無効になっている。
	FetchPOP は FetchMail 人気によって、現在ではオススメではない -->
    <fetchpop enabled="false">
        <!-- 複数のタスクを好きなだけ書けるが、それぞれユニークな識別名前が必要 -->
        <fetch name="mydomain.com">
            <!-- ホスト名かIPアドレス -->
            <host>mail.mydomain.com</host>
            <!-- ログインユーザ名 -->
            <user>username</user>
            <!-- ログインパスワード -->
            <password>pass</password>
            <!-- チェックの頻度(ミリ秒単位)。600000 だと10分おき -->
            <interval>600000</interval>
        </fetch>
    </fetchpop>

    <!-- これが FetchMail 設定の例。別なソースからメッセージを取ってきて自分の 
         スプールに入れる JavaMail ベースのゲートウェイ・サービスである。
	 普通に動くが、FetchMail は一般にエンベロープ情報をでっちあげる傾向が
	 ある。FetchMail は RFC 用語でいう「relay」というよりも、「mail gateway」
	 である。FetchMail は FetchPOP よりも多機能な代替品である。
	 要チェック:FetchMail はデフォルトで無効になっている。fetchmailConfig
	 と結び付いたファイルを編集して、有効にする必要がある。 -->
    &fetchmailConfig;

まあ、何のことはない。 XML のエンティティを使って、ファイルをインクルードしているに過ぎない。この部分を引用したのはそんなことよりも「エンベロープ情報をでっちあげる傾向がある」(原文だと「although FetchMail generally has to fabricate some of the envelope information.」)の方が原因だ。

後で見るが、受け取ったメールが「スパマーによっていい加減な Received: ヘッダを書かれている?」かどうかを検出する、などとちょっとお節介をしているために、実はあるケースで問題がでるのである。

james-fetchmail.xml の設定

いちゃもんはともかく、設定を先に進めよう。なのでエンティティの指定どおり、conf/james-fetchmail.xml を見るのだが、これもまた呆然とするくらいに設定項目が多い。さすがにタマンないので、コメントを全部外して掲載しよう。ここで日本語で入っているのは、筆者の説明用のパート分けでである。

<fetchmail enabled="false">
   <fetch name="mydomain.com">
      基本設定
      <accounts>
         <alllocal userprefix="" usersuffix="@myaccount"
                   password="password" recipientprefix=""
                   recipientsuffix="@mydomain.com" ignorercpt-header="true"/>
         <account user="myglobalaccount" password="password"
                   recipient="postmaster@localhost" ignorercpt-header="false"/>
      </accounts>
      <host>pop.server.com</host>
      <interval>600000</interval>

      接続などの詳細設定
      <javaMailProviderName>pop3</javaMailProviderName>
      <javaMailFolderName>INBOX</javaMailFolderName>
      <javaMailProperties>
        <property name="mail.pop3.connectiontimeout" value="180000"/>
        <property name="mail.pop3.timeout" value="180000"/>
      </javaMailProperties>

      メール処理全般
      <fetchall>false</fetchall>
      <recursesubfolders>false</recursesubfolders>
      メールごとの処理
      <fetched leaveonserver="false" markseen="true"/>
      <remotereceivedheader index="1" reject="true" 
                     leaveonserver="true" markseen="false"/>
      <maxmessagesize limit="0" reject="false" 
                     leaveonserver="true" markseen="false"/>
      <undeliverable leaveonserver="true" markseen="false"/>
      <recipientnotfound defer="true" reject="true"
                     leaveonserver="true" markseen="false"/>
      <blacklist reject="true" leaveonserver="true" markseen="false">
               wibble@localhost, flobble@localhost 
      </blacklist>
      <userundefined reject="true" leaveonserver="true" markseen="false" />
      <remoterecipient reject="true" leaveonserver="true" markseen="false" />
   </fetch>
</fetchmail>

まあ、こんな文書読む奴は、あまり細かいことを言っても「そんなん見りゃ判る!」って言いそうだから、「基本設定」とか「接続などの詳細設定」あたりで自明な説明は飛ばす。

基本設定

ポイントは <alllocal> タグと <account> タグがなんで両方あるの?という点だ。これは要するに「すべてのローカルユーザについて fetchする」(alllocal)と、「特定ユーザについてfetchする」(account)であり、言うまでもなくフツーは account タグの方を使うだろう。まあ、パターン一致で抽出する(allocal)のはあまり使い道がないかな?要するにエレメント数は allocal = 0,1, account = 0,1... なので、適当にどっちか使えばよい。accout タグの方を必要なだけ列挙する、というのが多分フツーだな。まあ、ここらへん「ユーザ混乱するぞ」というのがあるのか、conf/samples/fetchmail/ 以下に6つも設定例があるので、そっちを見たら安心だな。

メールごとの処理

さてこれは /usr/bin/fetchmail なんぞにはない機能だ。FetchMail は結構お節介なので、たとえば「ブラックリストに乗ってるユーザは受け取らない!」なんてことが、この FetchMail レベルで出来てしまう。まあ、そういうわけで、ここのパートのタグは大体属性仕様が共通している。

reject
==true なら、受け取らない
leaveonserver
==true なら、サーバ上から削除する。
markseen
「既読フラグ」を立てる。勿論ほとんどの POP3 サーバにはこんな洒落た機能はないので、現状ではまず働かない。

じゃあ、ここのタグの意味。

fetched
「成功時」。コメント不要。
remotereceiverheader
こいつはややこしい。要するにスパマ−が Received: ヘッダに細工をするのを検出するためにあるのである。内部的に RemoteReceivedHeaderIndex というメールごとの変数があり、これは送られて来たメールの Received: ヘッダの数(from とかが入っているもののみ)を勘定して、その値としている。もしスパマ−が「実際には外部MTAから出しているだけど、ローカルから届いたように見せかけよう!」とヘッダに細工をしても、ここで Received: ヘッダの数を勘定して、それと突き合わせる、というようなチェックをデフォルト設定でしている。まあ、このタグはデフォルトの設定どおりにしておくのが良かろう。このタグの設定がちょいとばかり謎なことを引き起こしたが、これは後で説明する。
maxmessagesize
サイズ制限を課す。limit 属性値よりもサイズが大きければ、このタグの指定による。
undeliverable
何かが起きて、配信できないケースに適用。
recipientnotfound
宛先が見つからないケースに適用。defer 属性があり、これが true だと「処理を送らせて次回にまた」。要するにアカウントを作る前にメールが届いているケースを想定しているな。
blacklist
「ブラックリスト」処理である。値として宛先をコンマ区切りで列挙する。内部の不良ユーザに届かないようにするわけである。
userundefined
ユーザが James の上で定義されていないケースに適用。
remoterecipient
配達されるべきユーザがリモートユーザであるケースに適用。リレーを排除するというような意図があるのだろうか?? まあ、それよりもこれに引っかかるのは単純に servernames タグの「受け取るべきドメイン名」の設定を間違ってるケースだろう。

トラブルシューティング

実は筆者はこの件で結構苦労したのである。

筆者の環境はいろいろと仕事をするために、非接続環境にしてある。なので、特にネームサーバは立てずにやっていたのだが、これが実は FetchMail 機能を使うとなると問題なのである。

まあ、基本的には James は「メールを受け取って...」という機能の方が、「メールを送る」機能よりも重要に決まっている。そりゃメールを出すのならば、「インターネットに接続してネームサーバから MX レコードを引けるように設定しなきゃね!」となるのだが、「メール受取側」ばっかりやっていたので、ネームサーバを特に立てていなかったのである。

実はこれだと意外なことに FetchMail が動かない。それは実は、先ほどの「remotereceivedheader」タグの処理と関連しているのである。実際、このタグがあるために、「メールの送り元がホントに正しいか?」をチェックしないといけないのである。

だから、メールの「Received:」ヘッダを見て、その転送元が改竄されているかどうかの簡単なチェックを行う。そのためには、ホスト名表記のたとえば「Received: from fmta04.dion.ne.jp ([210.155.124.184])」から、fmta04.dion.ne.jp を DNS 正引きを行って、IPアドレスを取得する([210.155.124.184] は偽造できるからね)必要があるのである。

こりゃ意外な落し穴だ。しかも、ログメッセージが要領を得ない。DNS を立てずに(言い替えれば /etc/host でレゾルヴする)フェッチすると、apps/james/logs/fetchmail-*.log が次のようなエラーを出す。そして、メールは fetch されないし、元のPOPサーバからは消えない。

09/12/05 12:13:32 INFO  fetchmail.jamestest.jp: Configured FetchMail fetch task jamestest.jp
09/12/05 12:13:32 INFO  fetchmail: FetchMail Started
09/12/05 12:14:32 INFO  fetchmail.jamestest.jp: Fetcher starting fetches
09/12/05 12:14:32 INFO  fetchmail.jamestest.jp: Processing 1 static accounts and 0 dynamic accounts.
09/12/05 12:14:32 INFO  fetchmail.jamestest.jp: Starting fetching mail from server 'localhost' for user 'news@jamestest.jp' in folder 'INBOX'
09/12/05 12:14:32 DEBUG fetchmail.jamestest.jp: Attempting delivery of message with id. <20051209030328.813.qmail@mydomain.jp>
09/12/05 12:14:32 INFO  fetchmail.jamestest.jp: Ignoring recipient header. Using configured recipient as new envelope recipient: sug@localhost. Message ID: <20051209030328.813.qmail@mydomain.jp>. Flags: Seen = false, Delete = false.
09/12/05 12:14:47 INFO  fetchmail.jamestest.jp: Rejected mail with an invalid Received: header at index 1. Message ID: <20051209030328.813.qmail@mydomain.jp>. Flags: Seen = false, Delete = false.
09/12/05 12:14:47 INFO  fetchmail.jamestest.jp: Processed 1 messages of 1 in folder 'INBOX'
09/12/05 12:14:47 INFO  fetchmail.jamestest.jp: Finished fetching mail from server 'localhost' for user 'news@jamestest.jp' in folder 'INBOX'
09/12/05 12:14:47 INFO  fetchmail.jamestest.jp: Fetcher completed fetches

エラーメッセージは何やら「Received:ヘッダの書き方が違う!」と言っているように見えるが、実は違う。これは単に DNS サーバが応答しないので、localhost -> 127.0.0.1 が解決できないでいるのである!

ふう...結構この件はソースを追いかけて「DNSサーバが立ってないから」という理由を解明したときには、思わず脱力したぞ。まあ、テスト環境でも bind を立ててくれ

ちなみに DNS サーバに関する James の設定(config.xml)は次の通りだ。

   <dnsserver>
      <servers>
         <!-- DNSサーバのIPアドレスを入れよ。server タグ
            1つにつきサーバ1件である -->
	 <!--
          <server>127.0.0.1</server>
	  -->
      </servers>
      <!-- autodiscover を false にするなら、手で servers
          タグに DNS サーバを設定する必要がある -->
      <autodiscover>true</autodiscover>
      <authoritative>false</authoritative>
   </dnsserver>

まあ、普通に DNSサーバが設定してあるのならば、autdiscover=true で十分だ。一応 /etc/resolve.conf だけを見て設定する旨のコメントがあるが、ネームサーバを利用しているのならば、フツー正しく設定してるよな。



copyright by K.Sugiura, 1996-2006