フレッツADSL導入日誌

remove-prepend for qmail

導入編
FreeBSDルーター編
ローカルDNSサーバー
フレッツADSLで固定IP
ドメイン取得とDNS運用
>>> メールサーバー / remove-prependパッチ
おまけ

27 Aug 2011 新規作成。

 netqmail-1.05用のパッチです。 netqmail-1.06でも平気だと思います。 作っておいて言うのもなんですが、「なくてもいいかなー」ってちょっと思ってたりして。

このソフトウェアは現状のまま提供されるものであり、このソフトウェアを使用した結果生じた直接的・間接的な、あるいはその他のいかなる損害に対しても、作者は責任を負いません。

BEFORE using the following patch, READ preamble of the patch.

netqmail-1.05-removeprepend-0.1.patch

 ~user/.qmailで転送を指示した場合に、~user/.qmail-ownerがあると、表書き差出人がuser-owner@example.jpの形に書き換えられます。 このアドレスは~user/.qmail-ownerの配送指示に従いますが、このファイルがあるからこのアドレスが生成されたので、必ず配送が可能です。

 一方、user@virtual.domaincontrol/virtualdomainsに合致するとprepend-プレフィックスが付けられて配送されます。 これはユーザーprependに配送され、~prepend/.qmail-user の配送指示に従います。

 もし、~prepend/.qmail-userで転送が指示されていて、~prepend/.qmail-user-ownerが存在すると、表書き差出人はprepend-user-owner@virtual.domainに書き換えられますが、このアドレスにメールを差し出すとcontrol/virtualdomainsによりさらにプレフィックスが付けられてしまい、prepend-prepend-user-owner@virtual.domain宛に配送されることになります。 このアドレスは~prepend/.qmail-prepend-user-ownerの配送指示に従いますが、普通このようなファイルはありませんから、このメールは正しく配送されません。

 また、prepend-というのは一種の内部情報で、外に漏れて欲しくない場合もあるでしょう。

 表書き差出人を書き換えているのはqmail-localです。 qmail-localが書き換えるときにcontrol/virtualdomainsを参照して、合致するアドレスの場合はprepend-部分を削除すればより望ましい動作になるでしょう。 ここでは、特定のドメインに対してのみ適用したい場合や、不具合があった場合に備え、control/removeprependというファイルを用いています。 Delivered-To:ヘッダフィールドにも同じようなアドレスが書かれます。 control/removeprependdtというファイルがあると、同様にDelivered-To:ヘッダフィールドに対してもprepend-プレフィックスを削除するようになります。

 control/removeprependcontrol/removeprependdtの形式はcontrol/virtualdomainsと同じです。 したがって、全仮想ユーザー・仮想ドメインに対して適用したい場合、control/virtualdomainsへのシンボリックリンクで済ませることができます。

 ひとつ制限があります。 仮想ドメインに対してはうまく動きます。 しかし、仮想ユーザーに対してはうまく動かないかもしれません。 例えば、

actual-user@virtual.domain:real
user@virtual.domain:real-actual

という記述があると、どちらの仮想ユーザーもreal-actual-user@virtual.domain宛に配送となります。 こうなってしまうとどちらのルールに合致してプレフィックスが付けられたのか区別がつきません。 プログラム上は配送されたアドレスに対し、

control/removeprependに対して順番に比較しているため、この場合は常にactual-user@virtual.domain:realが採用され、たとえuser@virtual.domainで受信した場合でも、転送時の表書き差出人はactual-user-owner@virtual.domainになってしまいます。

 アドレス全体は仮想ユーザーの例外に対してのみチェックされます。 アドレス全体がヒットして例外の指定ではない、つまり、prependがあるということは、もしこのルールにヒットしたら「prepend-アドレス全体」というアドレスになるはずです。 しかし、チェックしているのは「prepend-」がない「アドレス全体」ですから、一致することはありません。 したがって、アドレス全体を仮想ユーザー指定に対してチェックするのは意味がありません。

 仮想ドメインについては、ドメイン部は書き換えられないので、配送時にヒットしたルールは、qmail-localでも確実にヒットするはずです。 配送時にヒットしていなければqmail-localでもヒットしないはず。 したがって、仮想ドメインでは正確にprepend-を取り除いてくれるはずです。 virtualdomainsにはsub.example.jp.example.jpが指定してあるのに、removeprependには.example.jpしか指定してなかったりするとダメですが。

 あと、removeprependとは関係ありませんが、仮想ユーザーvirtual-user@virtual.domainに対して、virtual-user-onwer@virtual.domainのようなアドレスでメールを受けるには、このためのルール(仮想ユーザー・qmail-users機構など)が必要ですので、念のため。

 .qmailから起動するコマンドに渡される環境変数LOCAL・RECIPIENTはprepend部が付いたものが設定されます。 これはそのままの動作にしてあります。 一方、NEWSENDER・DTLINEはremoveprepend・removeprependdtにヒットするとprepend部を取り除いたものが設定されます。

 このパッチを当てなくても、~prepend/.qmail-userでqmail-injectの-fオプションで表書き差出人アドレスを差し替えれば解決します。 複数の宛先に転送したい場合は、qmail-injectで表書き差出人アドレスを書き換えた上で配送用のローカルなアドレスにメールを投げ、そのアドレスに転送先のアドレスを並べればOKです。 要するにメーリングリストと同じ要領です。

qmail-localとたわむれる

 動作の確認はてきとーにやってあります。 今回、Cygwin上でビルドして確認してみました。 以前はerr変数関係を修正しないとビルドが通らなかった覚えがありますが、net-qmail-1.05ならばほぼ普通にビルドできるようです。 ただし、ビルドコマンド生成シェルスクリプトとCygwinのテキストモードマウントの相性がよろしくないため、バイナリモードでマウントしたディレクトリでビルドした方がいいです。

 一部のコマンド・・・auto_uids.oをリンクしているコマンド・・・は説明どおりにユーザーIDを作らないとビルドできません。 qmail-localはやらなくてもビルドできるので今回はやっていませんが、Cygwinの/etc/passwdを編集してユーザーを作ればビルドできるのではないかと思います。 また、場合によってはファイルディスクリプタの数が足りないと言われるかもしれませんが、指示に従ってconf-spawnの数値を書き換えてやればOKです。 とりあえず今回はmake qmail-local一発で済んでしまいました。

 コンパイラのコマンドラインはconf-ccで設定できます。 gcc -O2だとふたつ警告が出ます。 ビルトイン関数と宣言がぶつかるという警告と、mainの戻り値がintじゃないという警告です。 試しに-Wも付けたらいっぱい警告が出てきたのでさっくり外しました(ぉぃ)。 -fno-builtin -Wno-mainを付けると警告は消えると思います、qmail-localをビルドしている範囲では。

 qmail-localは.qmailを読んで、mailbox・Maildirへの配送、コマンド実行、転送を行います。 配送は直接ファイルを操作します。 転送はqmail-queueを呼び出そうとします。 このふたつは動作テストにはちょっと都合が悪いです。 しかし、コマンド実行は好きなコマンドを実行して終了するため、動作確認にもってこいです。

 次に実行に必要なものを用意しなければなりません。 元々のqmail-localは制御ファイルを使いませんから、制御ファイルは用意する必要ありません。 メールを配送する場合はメールボックスが必要ですが、メールを配送しないのならこれも要りません。 ホームディレクトリはCygwinのものがそのまま使えます。 .qmailはコマンド実行を指定するのを適当に書いておきます。

 あとは入力メッセージが必要です。 これは標準入力へ入力しますが、シーク可能なストリームでなければなりません。 これは適当なメールメッセージをファイルとして作っておいて、リダイレクトすればOKです。 catしてパイプでつないだのではダメです。

 次。 コマンドラインを調べましょう。

qmail-local [ -nN ] user homedir local dash ext domain sender defaultdelivery

・・・引数、多いです。 -nを指定すると実際の実行をしません。 しかし、今回はコマンドを実行させたいので、これは指定しません(-Nが通常の動作で、デフォルトで指定されている状態です)。 userはメールが配送されるユーザー名、homdirはホームディレクトリなので、bashから実行するなら~userでOK、localはメールアドレスの@より前、dashとextは.qmailを決めるので、後で考えることにして、domainはメールアドレスの@より後ろ、senderは表書き差出人アドレスで、defaultdeliveryはmailbox形式なら./mailbox、Maildir形式なら./Maildir/ ですが、今回は配送はさせない予定なので、まあどっちでもいいです。

 で、dashとextですが、qmail-localは.qmailとして、homedir/.qmaildashextを探します。 これはuserがどうだろうが、localがどうだろうがこの名前です(実際にはdot-qmailのマニュアルに書いてある通り変換を受けます)。 で、dashが空の場合は.qmailファイルが見つからなかった場合に、空の.qmailファイルがあるのと同じ扱いになり、defaultdeliveryの指示に従うことになりますが、今回は.qmailが見つかってくれないと困るので、dashにハイフン、extに残りを指定すればいいです。

 qmail-usersのワイルドカード型割り付けで指定したpreはどこにいったかというと、これはqmail-sendがextにくっつけてqmail-localに渡しています。 なので、extpreをくっつけた状態で指定します。

 したがって、message.txt という内容のメールが joe@example.com から bob@example.jp へ送られ、virtualdomainsのbob@example.jp:userに引っかかってuser-bob@example.jpとなり、user宛に配送されて~user/.qmail-bob の配送指示に従う場合、

qmail-local user ~user user-bob - bob example.jp joe@example.com ./Maildir/ < message.txt

 .qmail中で指定したコマンドは、sh -cの引数として渡され、メールメッセージは標準入力で渡されます。 この例で.qmailに|/bin/catとでも書いておけば、message.txtの内容が表示されるでしょう。 |/bin/echo "$NEWSENDER"と書いておけば、環境変数NEWSENDERの内容が表示されるでしょう。 あとは好きなだけコマンドラインをいぢるなり、.qmailをいぢるなりしてください。

Copyright (C) 2011 You SUZUKI

$Id: remove-prepend.htm,v 1.4 2017/05/17 07:51:05 you Exp $

ひっそりとえいごも書いてみた