procmail をvirtual環境で使いたい
届いたメールを携帯で見たいというときに、できるだけ最小限のものにしたいと思って、procmailを利用してきた。こちらは、ホワイトリスト形式で広告などが配信されるようなパターンは除外している。主に顧客や非常時の連絡に使われるFromアドレス、ドメイン名を登録していくパターンで構成。
今まではOSアカウント=メールアカウントだったので、問題はなかったが、virtual環境にしたことでOSユーザーが1つになったことによるトラブルを体験した。そのことを中心にまとめてみた。
procmailの導入
# dnf install procmail
OS提供のパッケージを入れる。色々な方法があると思われるけれど、virtual環境で導入されたprocmailを参考に入れていった。
参考:Debian squeezeでvirtual mailにprocmail: 引き籠もりっぽい主夫のメモ帖
参考:Postfix + MySQL 環境で Procmail | あたがわの日記
この仕組みを文字に起こすと下記の通り。
- Postfixがメールを受け取り、local(自分自身)/virtual の配送と判断する。
- virtual環境では「virtual_transport = procmail」の設定にて配送処理を決める。
- 「/etc/postfix/master.cf」に記載されているprocmail の記述に従って、procmailを起動する。
「user=vmail argv=/usr/bin/procmail -t -m USER=${user} EXTENSION=${extension} /etc/procmailrc」 - 「/etc/procmailrc」には引き渡されたUSER変数に従って、.procmailrcファイルを探し、存在したらそれに処理を引き渡す。(僕が定義したファイル位置はこれ。/var/spool/mail/vhosts/$DOMAIN/$USER/.procmailrc)
図に書き起こすと下記の通り。

関係している設定ファイル
/etc/postfix/main.cf
# postconf -e virtual_transport=procmail
# postconf -n | grep virtual_transport
virtual_transport = procmail
変更はpostconfコマンドを利用して設定。
/etc/postfix/master.cf
これもコマンドを利用して設定する。参考にしたのはこのサイト。Change postfix master.cf with postconf – Mind IT
-Mで作って、-Pでオプションを追加するという仕組みらしい。でも今回のprocmailの記述は-o の部分がなかったので、-Mで全部入力する形になった。
# postconf -M procmail/unix=”procmail unix – n n – – pipe flags=R user=mailuser argv=/usr/bin/procmail -t -m USER=${user} DOMAIN=${nexthop} /etc/procmailrc”
設定されているか確認するには-M 以外の入力をしなければ、一覧表示される。
# postconf -M
smtp inet n – n – – smtpd
submission inet n – n – – smtpd -o smtpd_sasl_auth_enable=yes
smtps inet n – n – – smtpd -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes
pickup unix n – n 60 1 pickup
cleanup unix n – n – 0 cleanup
qmgr unix n – n 300 1 qmgr
tlsmgr unix – – n 1000? 1 tlsmgr
rewrite unix – – n – – trivial-rewrite
bounce unix – – n – 0 bounce
defer unix – – n – 0 bounce
trace unix – – n – 0 bounce
verify unix – – n – 1 verify
flush unix n – n 1000? 0 flush
proxymap unix – – n – – proxymap
proxywrite unix – – n – 1 proxymap
smtp unix – – n – – smtp
relay unix – – n – – smtp -o syslog_name=postfix/$service_name
showq unix n – n – – showq
error unix – – n – – error
retry unix – – n – – error
discard unix – – n – – discard
local unix – n n – – local
virtual unix – n n – – virtual
lmtp unix – – n – – lmtp
anvil unix – – n – 1 anvil
scache unix – – n – 1 scache
procmail unix – n n – – pipe flags=R user=vmail argv=/usr/bin/procmail -t -m USER=${user} DOMAIN=${nexthop} /etc/procmailrc
postlog unix-dgram n – n – 1 postlogd
間違えてしまったときなど、項目削除をするときには-MX のオプションをつかう。(入力しなおしを何度もやったので覚えた。procmail をTYPOしてprcomailとかの時とかも)
# postconf -MX “procmail/unix”
/etc/procmailrc
SHELL=/bin/bash
PATH=/usr/bin:/usr/local/bin
MAILDIR=/var/spool/mail/vhosts/$DOMAIN/$USER
DEFAULT=$MAILDIR/
LOCKFILE=/var/spool/mail/vhosts/procmail.lock
LOGFILE=/var/spool/mail/vhosts/procmail.log
VERBOSE=ON
:0
* ? test -e “$MAILDIR/.procmailrc”
| /usr/bin/procmail -t -m USER=$USER DOMAIN=$DOMAIN $MAILDIR/.procmailrc
多分ほかのサイトとかなり違う部分に赤字を入れた。通常はこんな構造はしていないと思う。
/var/spool/mail/vhosts/r******.jp/r****/.procmailrc
伏字にする必要はないんだけど、**** のところはドメイン名だったりユーザー名だったりがはいるので固定ファイル名じゃないから伏せてみた。ほんの一部を抜粋したんだけれど、特定のドメイン名からのメールを別アカウントに転送しているというもの。
SHELL=/bin/bash
PATH=$HOME/bin:/usr/bin:/usr/local/bin
MAILDIR=/var/spool/mail/vhosts/$DOMAIN/$USER
LOGFILE=$MAILDIR/procmail.log
LOCKFILE=$MAILDIR/.lockfile
DEFAULT=$MAILDIR/
NULL=/dev/null
:0 c
* 9876543210^0 ^From:.notify@twitter.com.
* 9876543210^0 ^From:.@microsoft.com.
* 9876543210^0 ^From:.@portal.eltax.jp.
* 9876543210^0 ^From:.@sg-m.jp.
* 9876543210^0 ^From:.@qiita.com.
* 9876543210^0 ^From:.@tribeat.com.
* 9876543210^0 ^From:.@bizstation-ml2.bk.mufg.jp.
! r****-.**.****@redalarm.jp
procmailのテスト方法について
以前から、procmailをテストするのに毎回メールを送っていては大変だったり、メーラーによって条件が変わってしまったり、文字エンコードのテストをしたいのに適切なデータを作りにくいなどの問題があり、コマンドライン上でできる方法を使っていた。(参考にしたサイトがあるはずなんだけど、かなり前の話で思い出せない)
# cat a.txt | sudo -u r**** /usr/bin/procmail
通常は上記のような形でa.txtはメールのソースそのまま。root実行、sudoでprocmail 起動、そのユーザーのホームディレクトリにある.procmailrcが起動されるという流れだったんだけど、今回はvirtual環境なのでやり方が変わったところを記載する。
# cat a.txt | sudo -u vmail /usr/bin/procmail -t -m USER=r***** DOMAIN=r******.jp /etc/procmailrc
上記のように、vmailユーザーで起動して、環境変数にバーチャルのユーザーを指定する。procmailrcは一段階目のファイルを指定する。
virtual環境に入れたprocmailで発生したトラブル
このドメインにはユーザーが少ないので、面倒くさがってメーリングリストのソフトウェアを入れていなかった。/etc/aliasesに複数のユーザーを記載することで簡易的に複製するだけとしていた。今回も移行にあたり、同様の設定ができればと考えていた。
virtual環境では、/etc/aliasesでの複製ができないということが検証によってわかっていたので、/etc/postfix/virtualのファイルの中でメールの複製をしようと試みた。で、それはprocmailを導入する前にテストをしていたので、問題ないかに見えていた。
/etc/postfix/virtual に記載したのはこんな感じ。
furitest@redalarm.jp acc1@redalarm.jp acc2@redalarm.jp acc3@redalarm.jp
下記のログを見る限りは正常に届いているように見える。
Jun 8 09:07:33 mail postfix/smtpd[239823]: connect from unknown[240f:73:17ee:1:dd14:6b2d:89cc:c59]
Jun 8 09:07:33 mail postfix/smtpd[239823]: 3E780F969B: client=unknown[240f:73:17ee:1:dd14:6b2d:89cc:c59], sasl_method=PLAIN, sasl_username=rebine@redalarm.jp
Jun 8 09:07:33 mail postfix/cleanup[239826]: 3E780F969B: message-id=20210608090734.7B2D.76D2DE17@redalarm.jp
Jun 8 09:07:33 mail opendkim[728]: 3E780F969B: DKIM-Signature field added (s=s20210501, d=redalarm.jp)
Jun 8 09:07:33 mail postfix/qmgr[213540]: 3E780F969B: from=r12345@redalarm.jp, size=837, nrcpt=3 (queue active)
Jun 8 09:07:33 mail postfix/pipe[239827]: 3E780F969B: to=acc3@redalarm.jp, orig_to=furitest@redalarm.jp, relay=procmail, delay=0.15, delays=0.15/0/0/0, dsn=2.0.0, status=sent (delivered via procmail service)
Jun 8 09:07:33 mail postfix/pipe[239827]: 3E780F969B: to=acc1@redalarm.jp, orig_to=furitest@redalarm.jp, relay=procmail, delay=0.15, delays=0.15/0/0/0, dsn=2.0.0, status=sent (delivered via procmail service)
Jun 8 09:07:33 mail postfix/pipe[239827]: 3E780F969B: to=acc2@redalarm.jp, orig_to=furitest@redalarm.jp, relay=procmail, delay=0.15, delays=0.15/0/0/0, dsn=2.0.0, status=sent (delivered via procmail service)
Jun 8 09:07:33 mail postfix/qmgr[213540]: 3E780F969B: removed
Jun 8 09:07:33 mail postfix/smtpd[239823]: disconnect from unknown[240f:73:17ee:1:dd14:6b2d:89cc:c59] ehlo=2 starttls=1 auth=1 mail=1 rcpt=1 data=1 rset=1 quit=1 commands=9
でも実際に各ユーザーのディレクトリを見てみると、acc3にしかメールは届いていなった。ログで最初に記述されているユーザーしか届かない。procmailは重複メールを削除しないし…さっぱり訳が分からなかったが、原因が判明した。
procmailはロックする機能がある。同時に複製されたメールを処理しようとすると、ロックされてしまって2つ目3つ目のメールは処理されていない様子が出てきた。(procmail をVERBOSEモードにしてログを見た)
理由はprocmailがEOF区切りで動作するからと推測。追記(2021/9/11)にて記載した。
procmail: [240095] Tue Jun 8 09:23:51 2021
procmail: Executing “test,-e,/var/spool/mail/vhosts/r ***** .jp/r ***** /.procmailrc”
procmail: [240095] Tue Jun 8 09:23:51 2021
procmail: Match on “test -e /var/spool/mail/vhosts/r ***** .jp/r*****/.procmailrc”
procmail: Assigning “LASTFOLDER=/usr/bin/procmail -t -m USER=r ***** DOMAIN=r ***** .jp /var/spool/mail/vhosts/r ***** .jp/r ***** /.procmailrc”
Subject: test20210608-04
Folder: /usr/bin/procmail -t -m USER=r ***** DOMAIN=r ***** .jp /var/ 1242
procmail: Unlocking “/var/spool/mail/vhosts/procmail.lock“
procmail: Executing “/usr/bin/procmail,-t,-m,USER=rebine,DOMAIN=redalarm.jp,/var/spool/mail/vhosts/r ***** .jp/r ***** /.procmailrc”
図にするとこんな感じに。

これは、一度vmailユーザーのprocmailrc で処理をさせて、そのあとで個々のユーザーのprocmailが起動するという構造が起因となったトラブルだとわかった。
と、断定したのは誤りで、procmailは起動時にEOFまでを処理対象として設計されているし、master.cfで定義される配信先には複数のメールをまとめて標準入力に送るという設計だったからだった。
トラブルの回避方法
メール振り分け専用のユーザーを作って、複製したい場合はそのユーザーに。で、そのユーザーのprocmailrcにそれぞれのユーザーを記載した。
furitest@xxxxx.jp → furiwake@xxxxx.jp
furiwake のprocmailrc には、下記のように記載。
:0 c
* $ ^To:.*furitest@r******.jp
! acc1@redalarm.jp acc2@redalarm.jp acc3@redalarm.jp
ちょっと面倒になった気がするけれど、今から設計を変えるのもなーっていう感じで仕方ない。
試していないトラブルの回避方法
すべてのユーザーにprocmailrcを作ればよいのでは?と思ったけれど。ユーザー作成スクリプトなりに.procmailrc を基本的に作るような記述をするという回避方法もあると思った。
これを試したが結果は変わらなかった。
懸念点
もしこの状態で、mailman とかFMLなどのalias設定との絡みがあるようなメーリングリストソフトウェアを入れた場合、どのように動くことになるのかな?という懸念が生まれてしまう。(最初にprocmailには任せないだろうから大丈夫だとは思うんだけれど…メールは1通ずつメーリングソフトウェアが複製していくと思うので…)
追記(2021/9/11)
procmailのlock機構がこの状態を生んでいると思い込んでいたが、下記の2つの作業を試してみても解決しなかった。
1.ロックファイル名にユーザー名を追加して生成
2.すべてのユーザーに.procmailrcを設定し、/etc/procmailrc を経由せずに各ユーザの.procmailrc 読み込んで起動
https://manpages.debian.org/unstable/manpages-ja/procmail.1.ja.html
こちらに、procmailはメールをEOFまで読み込んで…とある。なので、1つのメールとして認識される区切りがEOFだとすると、2通、3通のメールをまとめてmaster.cfに記載された形の配送先として標準入力に出されれば1通しか処理ができないということも想像がつく。
ロックファイルにユーザー名を追加する設定
[root@mail ~]# cat /etc/procmailrc
SHELL=/bin/bash
PATH=/usr/bin:/usr/local/bin
MAILDIR=/var/spool/mail/vhosts/$DOMAIN/$USER
DEFAULT=$MAILDIR/
LOCKFILE=/var/spool/mail/vhosts/procmail.lock.$USER
LOGFILE=/var/spool/mail/vhosts/procmail.log
VERBOSE=ON
:0
* ? test -e “$MAILDIR/.procmailrc”
| /usr/bin/procmail -t -m USER=$USER DOMAIN=$DOMAIN $MAILDIR/.procmailrc
すべてのユーザーに.procmailrcを設定して個別procmail起動
procmail unix – n n – – pipe flags=R
user=vmail argv=/usr/bin/procmail -t -m USER=${user} DOMAIN=${nexthop}
/var/spool/mail/vhosts/${nexthop}/${user}/.procmailrc