このエントリは 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 の両方の処理を行うことはできないかどうかを試してみました。
黒魔術の例
- 特定アドレス、なおかつ特定の日本語件名の場合は任意のスクリプトを実行
- Sieve の Pipe プラグイン を使えばなんとかなるのかも知れません。if に pipe 使えるのかな。結局、どっちでやっても黒魔術っぽくなってしまうと思いますが…
:0 c
* ^From: .*[email protected]
* ^Subject: /.*
* ? echo "$MATCH" | nkf -mZ1 --utf8 | grep '100万円差し上げます'
| /opt/scripts/bin/notify.sh
検証環境
- 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 は省略しています。
local はメッセージの書き込みを単独で行うこともできますが、外部プログラムに書き込みを任せることもできます。外部プログラムの代表的な例としてmaildrop, procmail, dovecot-lda, dovecot-lmtp などが挙げられます。なお、 dovecot-lmtp はローカル以外にも配送可能です。
設計
今回の設定のポリシーは以下の通りです。
- すべてのユーザのローカル配送を dovecot-lmtp が行う
- 特定ユーザに対するメールを毎回 procmailrc と dovecot-lmtp の両方に食わせる
local は、以下の流れで処理を行います。
- エイリアスの評価
- .forward の評価
- ローカル配送
local の動作の2つ目である「.forwardの評価」において、パイプで procmail に渡せばいいように思えますが、.forward で procmail を実行すると処理 3 が実行されないまま local は処理完了となります。そのため、今回は特定アカウントに対するメールを複製し、別アカウントで procmail の処理を行うように設定をしました。
メール処理のフローは以下の通りです。メール振り分け用アカウント(Sieve)は test1、スクリプト実行用アカウント(procmail)は test2 です。
- 特定アカウントへのメールに対して procmail を処理するためのアカウントを作成
- recipient_bcc_maps にて特定アカウントのメールの BCC に procmail 用のアカウントのアドレスを挿入
- test1 への配送時、 Sieve が呼び出される
- test2 への配送時、.forward が読み込まれ、procmail が呼び出される
メールを複製するのは 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" "[email protected]" { 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 を用いた
-
黒魔術ほんとよくない