Postfix のサンドボックス環境をローカルに作る

この記事は「はてなエンジニア Advent Calendar 2022」の 23 日目の記事です。 昨日は id:onishi さんで はてなのエンジニア×人事の取り組み - 大西ブログ でした。

訳あって Postfix を勉強しています。

Postfix 実用ガイド などを参考に Postfix を動作させてみようと思ったのですが、インターネットを経由した場合のメールの送受信は準備や設定が大変そうでした。このため、メールの送受信などをローカルで試せる Postfix サンドボックス環境を作ってみることにしました。

サンドボックス環境の概要

  • リポジトリhiroygo/postfix-local です
  • docker compose でメール送信用 Postfix コンテナとメール受信用 Postfix コンテナを起動します
  • メール送信用コンテナのホスト名を send.localhost、メール受信用コンテナのホスト名を recv.localhost としてます。2 つのコンテナは共通の docker network で接続されているため、互いのコンテナを名前解決できます
  • メールの送信では、メール送信用コンテナ内で Postfix sendmail コマンドを実行します。これによりメールがメール送信用コンテナからメール受信用コンテナに送信されます。送信者は root@send.localhost で、受信者は root@recv.localhost です

メールを送受信してみる

make send-mail でメールを送信して、make show-recv-mail で受信したメールを確認できます。もし root ユーザ(root@recv.localhost)以外に送信したい場合はユーザの追加が必要になります。ログは make log-sendmake log-recv で確認できます。

% make up 
...
  
% make send-mail 
...
  
% make show-recv-mail
docker compose exec -it recv.localhost cat /var/spool/mail/root
From root@send.localhost  Sat Dec 10 08:10:53 2022
Return-Path: <root@send.localhost>
X-Original-To: root@recv.localhost
Delivered-To: root@recv.localhost
Received: from send.localhost (unknown [172.22.0.3])
    by recv.localhost (Postfix) with ESMTPS id A34C812EF3F
    for <root@recv.localhost>; Sat, 10 Dec 2022 08:10:53 +0000 (UTC)
Received: by send.localhost (Postfix, from userid 0)
    id 95DFA12EF02; Sat, 10 Dec 2022 08:10:53 +0000 (UTC)
From: root@send.localhost
To: root@recv.localhost
Subject: this is subject
Message-Id: <20221210081053.95DFA12EF02@send.localhost>
Date: Sat, 10 Dec 2022 08:10:53 +0000 (UTC)

this is body.

% make log-send 
docker compose logs send.localhost
postfix-local-send.localhost-1  | Dec 10 08:10:29 send postfix/postfix-script[102]: starting the Postfix mail system
postfix-local-send.localhost-1  | Dec 10 08:10:29 send postfix/master[103]: daemon started -- version 3.5.13, configuration /etc/postfix
postfix-local-send.localhost-1  | Dec 10 08:10:53 send postfix/pickup[104]: 95DFA12EF02: uid=0 from=<root>
postfix-local-send.localhost-1  | Dec 10 08:10:53 send postfix/cleanup[114]: 95DFA12EF02: message-id=<20221210081053.95DFA12EF02@send.localhost>
postfix-local-send.localhost-1  | Dec 10 08:10:53 send postfix/qmgr[105]: 95DFA12EF02: from=<root@send.localhost>, size=307, nrcpt=1 (queue active)
postfix-local-send.localhost-1  | Dec 10 08:10:53 send postfix/smtp[116]: 95DFA12EF02: to=<root@recv.localhost>, relay=recv.localhost[172.22.0.2]:25, delay=0.06, delays=0.01/0.02/0.02/0.01, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as A34C812EF3F)
postfix-local-send.localhost-1  | Dec 10 08:10:53 send postfix/qmgr[105]: 95DFA12EF02: removed

サンドボックス環境は役に立ったか

master デーモン だけでなく、smtpsmtpd の動作やログも確認できて、勉強になりました。ただサンドボックス環境の構築が思ったより大変で、構築のために試行錯誤してたら、だいぶ Postfix の勉強ができてしまった感があります...

細かいこと

  • Postfix 公式の Docker イメージはなさそうだったので、普通に apt-get install してます
  • メール送信用コンテナ、メール受信用コンテナとも main.cf はほぼデフォルトです。変更点は以下を見てもらえるとわかります
  • recv.localhost 用の MX レコードの設定は不要です。Postfix はメール送信時、 MX レコードが無いと A レコードから、送信先を決定するっぽいです
  • send/run.sh
    • メール送信用コンテナでは、このスクリプトから Postfixmaster デーモン を起動します
    • コンテナ終了時は shutdown_handler でシグナルを受け取り postfix stop で master デーモンと、その子プロセスを終了させます。master デーモンのソースコードをみた感じ、子プロセスの終了を待機してなさそうなので、スクリプト側で待機処理を入れています
    • Postfix は名前解決に /var/spool/postfix/etc/resolv.conf を使うので、Postfix 起動前に /etc/resolv.con をコピーしています。/etc/resolv.conf はコンテナ起動時に書き換えられるため、コンテナ起動後にコピーします。コピーではなくシンボリックリンクでもいいと思います

はてなエンジニア Advent Calendar 2022、明日は id:yutailang0119 さんです!