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

December 21, 2014

このエントリは 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 はローカル以外にも配送可能です。

mail_application

設計

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

  • すべてのユーザのローカル配送を 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" "[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 を用いた
  • 黒魔術ほんとよくない

参考URL


Profile picture

Written by Narimichi Takamura (@nari_ex) who works at Topotal as CEO. He love engineering and fighting game.