PHPとsendmailで任意のメールアドレスに来たメールを処理する方法

SPONSORED LINK

Pocket

check*padのサーバー騒動でまとめたくなったので自分メモも兼ねてまとめてみます。これがわからなくてちょっとはまったので・・・。

■ やっていることの概要

check*padではリストごとにxxxxxxxxxxxxxxxx@checkpad.jpなるアドレスを発行し、そこにメールを送ると本文を解析してTo Do項目を追加してくれます。このように@checkpad.jp以前が可変の場合、どのように処理するかの説明です。

■ 作業手順

では順を追って作業を見ていきます。

  1. /etc/aliasesを変更
  2. まず、ダミーのアドレスをつくり(この場合、madd)、/etc/aliasesに追加します。追加する際にはPHPのプログラムにパイプするようにします。

    madd: "|/usr/bin/php -f /home/hogehoge/checkpad.jp/foo/process_mail.php"
    

    追加したあとはnewaliasesを忘れずに。

    ※ ちなみにメールアドレスの@以前が不変の場合、この一行でPHPにそのまま渡せます。

  3. smrshにリンクを追加
  4. sendmailのシェルがPHPにアクセスできるように以下のように設定。

    #ln -s /usr/local/bin/php /etc/smrsh/php
    
  5. sendmail.cfの変更
  6. 次に/etc/mail/sendmail.cfを変更し、定義されていないメールアドレスにメールが来たらどこに飛ばすかを設定します(この場合、maddに全部飛ばしています)。

    参考にしたのは「Configuring sendmail on Solaris 7 and Solaris 8 to accept incoming email」(赤松さんに教えてもらいました、感謝!)。

    作業は二つほど。

    • 変更その1
    • 以下のコードの直下に、次のコードを挿入。

      # "Smart" relay host (may be null)
      DSyour ISP's smart mail host
      (の直下に次)
      # place to which unknown users should be forwarded
      Kuser user -m -a<>
      # deliver mail for unknown users to postmaster locally
      DLlocal:madd
      

      maddの部分は適宜変えてください。

    • 変更その2
    • またしてもコード追加。

      ###########################################################################
      ###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
      ###########################################################################
      (中略)
      # prepend an empty "forward host" on the front
      R$+     $: <> $1
      (の直下に次)
      # send unrecognized local users to a relay host
      R< > $+     $: < $L . > $(user $1 $)  look up user
      R< $* > $+ <> $*  $: < > $2 $3      found; strip $L
      R< $* . > $+    $: < $1 > $2      strip extra dot</pre>
      
    これでサーバー側の設定は終了。sendmailを再起動しておきます。
  7. さて、PHP
  8. では次に最終的に処理をするprocess_mail.phpを書いていきます。ざっくりコードはこんな感じ。
    // 標準出力から読み取り
    $fd = fopen("php://stdin", "r");
    $email = "";
    while (!feof($fd)) {  $email .= fread($fd, 4096);  }
    fclose($fd);
    // TO:アドレスの取得
    if (preg_match ('/[\n\r]To:.*([a-f0-9]{32})'.’@checkpad.jp'.'/', $email, $matches)) {
      $to_address = $matches[1];
    } else {
      mail ("me@mail.com", "Failed to capture mail", $email, "From: me@mail.com");
      exit;
    }
    // 件名、本文の抽出
    $maildata = preg_split ("/\n\n/", $email); // $maildata[0]が件名、[1]が本文
    // あとはこれらのデータを使ってごにょごにょ・・・。
    

    ↑ あ、ちょっと違うな。@以前のメアドはこの場合、32桁の英数字に限定ですね・・・ま、そこらへんは各自で工夫してください。

    なんかPEARとか使うともっとスマートにいくっぽいですが・・・ご容赦を。なんか正規表現gdgdっすね・・・。

  9. テスト
  10. あとはメールを送ってみてテストします。tail -f /var/log/maillogをみながらちゃんとメールが受け取られているかをチェックしましょう。

    なお、unknown mailer errorとか出たらPHPにバグがある可能性大です。ウォッチポイントを設定してログを吐き出したりしつつ、ちゃんとデバッグしましょうね。

以上、簡単に説明してみました。うまく動いているのであまり考えていないのですが、もしかしたらもっとスマートな方法があるのかもしれません・・・あれば是非教えてください。

ツイッターもやっています!

SPONSORED LINK

  1. あ、、、

    sendmail.cf をいじるのは古い方法で・・・これ紹介するのは ちょっと地雷です。です。

    今は virtusertable をさっくり変更するだけで対応できます。。。具体的な方法は誰かがすぐにトラックバックしてくれると思いますが・・・

  1. No trackbacks yet.