1通のメールに対して procmail と Sieve の処理を両立させる


このエントリは Postfix Advent Calendar 2014 の21日目です。

動機

Postfix の設定の1つにローカル配送があります。Postfix では外部プログラムを用いてローカル配送を行うことができます。何が一般的に使われているのかわからないのですが、おそらく procmail か dovecot-lda、最近だと dovecot-lmtp を使っているのではないのでしょうか。

自分の環境では、今まで procmail を使ってローカル配送をしていました。しかし、MRA(POP, IMAPサーバ)にせっかく dovecot を使っているので dovecot-lmtp に移行しました。procmail によるメール配送はメールロストの危険性があるのでやめたかったというのも理由の1つです。

しかし、procmail → dovecot-lmtp への移行時に億劫だったのが古(イニシエ)の procmailrc の移行です。振り分けに関する設定は比較的簡単に Sieve に移行できるかもしれませんが、黒魔術化した procmailrc はあまり手をつけたくないです。
そのため、特定アカウントに対する 1 つのメールに対して、procmail と Sieve の両方の処理を行うことはできないかどうかを試してみました。

黒魔術の例

:0 c
* ^From: .*hoge@hoge.jp
* ^Subject: /.*
* ? echo "$MATCH" | nkf -mZ1 --utf8 | grep '100万円差し上げます'
| /opt/scripts/bin/notify.sh

※特定アドレス、なおかつ特定の日本語件名の場合は任意のスクリプトを実行
※なお、確認してませんが Sieve の Pipe プラグイン を使えばなんとかなるのかも知れません。if に pipe 使えるのかな。結局、どっちでやっても黒魔術っぽくなってしまうと思いますが...

検証環境

  • OS: CentOS release 6.6 (Final)
  • Postfix: 2.6.6
    • dovecot-lmtp は設定済み
  • Dovecot: 2.0.9
  • procmail: 3.22

メール設定環境は、単一ドメイン設定でありバーチャルドメインを利用していません。

Postfix における内部配送の仕組み

今回は Postfix のローカルスプールに配送を行う MDA にフォーカスします。

Postfix は以下の図に示す通り、いくつかのサブシステムによって構成されています。Postfix に含まれる MDA のうち、ローカル(ホスト内)のメールスプールに書き込みを行うサブシステムは local と virtual です。今回はバーチャルドメインの設定を前提としていないため、virtual は省略しています。

mail_application

local はメッセージの書き込みを単独で行うこともできますが、外部プログラムに書き込みを任せることもできます。外部プログラムの代表的な例としてmaildrop, procmail, dovecot-lda, dovecot-lmtp などが挙げられます。なお、 dovecot-lmtp はローカル以外にも配送可能です。

設計

今回の設定のポリシーは以下の通りです。

  • すべてのユーザのローカル配送を dovecot-lmtp が行う
  • 特定ユーザに対するメールを毎回 procmailrc と dovecot-lmtp の両方に食わせる

local は、以下の流れで処理を行います。

  1. エイリアスの評価
  2. .forward の評価
  3. ローカル配送

local の動作の2つ目である「.forwardの評価」において、パイプで procmail に渡せばいいように思えますが、.forward で procmail を実行すると処理 3 が実行されないまま local は処理完了となります。
そのため、今回は特定アカウントに対するメールを複製し、別アカウントで procmail の処理を行うように設定をしました。

メール処理のフローは以下の通りです。

メール振り分け用アカウント(Sieve): test1
スクリプト実行用アカウント(procmail): test2

  1. 特定アカウントへのメールに対して procmail を処理するためのアカウントを作成
  2. recipient_bcc_maps にて特定アカウントのメールの BCC に procmail 用のアカウントのアドレスを挿入
  3. test1 への配送時、 Sieve が呼び出される
  4. test2 への配送時、.forward が読み込まれ、procmail が呼び出される

flow

メールを複製するのは smtpd サブシステムです。このサブシステムは、先ほどの図の通り、local よりも処理が先に行われます。test1 の処理の過程で .forward の評価は行われますが、ここでは procmail に渡す設定をしないため、そのまま次の処理に移行して外部プログラム(今回は dovecot-lmtp)が呼び出されます。これにより、Sieve によるメール振り分けが実行されます。test2 の処理では、.forward によって procmail を実行することでメール受信にフックをしてスクリプトを実行します。上述の通り、procmail 処理後に外部プログラムは呼び出されません。

検証

以下の設定を行い、メール配送のテストを行いました。

BCC 挿入設定

  • main.cf
recipient_bcc_maps = hash:/etc/postfix/recipient_access
  • recipient_access
# cat /etc/postfix/recipient_access
test1    test2

メール振り分け用アカウントの設定

  • test1 の .dovecot-sieve
# cat /home/test1/.dovecot.sieve
require "fileinto";
if address :is "from" "test3@hoge.com" {
        fileinto "INBOX.test";
} else {
        keep;
}

スクリプト実行用アカウントの設定

  • test2 の .forward
"|/usr/bin/procmail -f-"
  • test2 の .procmailrc
#:0
#* ^Subject.*test
#| /home/test2/test.sh
  • test.sh
#!/bin/bash

touch /tmp/hoge
exit 0

結果、無事に test1 のメール振り分けが行われ、なおかつ /tmp/hoge が作成されていました。

まとめ

  • 特定アカウントに対する1つのメールに対して procmail と Sieve の両方を実行する設定を行った
    • Postfix の設定に recipient_bcc_maps を用いた
  • 黒魔術ほんとよくない

参考URL

ASCII.jp: メールを受け取る仕組みはどうなっていますか??
Pigeonhole Sieve Interpreter


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Time limit is exhausted. Please reload CAPTCHA.