Docker で MailHog コンテナを作る方法
Docker の PHP コンテナで開発する際に、PHP のメール送信関数 mail() もしくは mb_send_mail() を使うと、エラーが出てしまい困ることがあります。
とはいえ、本物のメールサーバーを用意するわけにもいきません。
開発時にはメールが外部に送信されてしまうと困ります。
メールを外部に送信せずに、メールの動作確認をしたい場合はどのようにすればよいでしょうか。
MailHog とは?
MailHog はテスト用に開発されたメールサーバーです。 Go 言語で実装されています。 本物のメールサーバーのように振舞いながらも、メールを外部には送信しませんので、メールの動作確認をする場合はとても便利です。
Docker で MailHog コンテナを作る
Docker で MailHog のコンテナを作成してみましょう。
コンテナのイメージは、下記のイメージを使用します。
イメージのバージョン(タグ)は特にこだわりが無ければ最新版(latest)で良いと思います。
MailHog のコンテナの中には、メールを受け取る用の SMTP サーバーと、受け取ったメールの内容を表示するための Web サーバーが含まれています。
MailHog の Web サーバーのコンテナ側のポート番号は 8025 番です。 80 番ではないので注意してください。 ホスト側から Web ブラウザ(Chrome など)で接続できるよう、コンテナ側のポート 8025 番へのマッピングを設定しましょう。 ホスト側のポート番号は、他で使用されていないものなら何番でも良いと思います。
PHP から MailHog コンテナにメールを送る方法は後述します。
version: "3.8"
services:
# MailHog コンテナ
mailhog:
image: mailhog/mailhog:latest
ports:
- 18025:8025
データが消えないようにする
MailHog はデフォルトではメモリにメールデータを保存するため、コンテナを再起動すると受け取ったメールが消えてしまいます。 また、Docker がコンテナを再作成したりした場合も同様に、受け取ったメールが消えてしまいます。 MailHog の主な用途は開発時のテストだと思いますので、メールが消えて困る場面は少ないと思うのですが、 メールが消えてしまうと困るという場合は、消えないように設定しましょう。
メールをファイルに保存する
メールが消えないようにするためには、メールをメモリではなくファイルに保存させる必要があります。
なお、現状の MailHog では、メールをファイルに保存するように設定すると、 メールが日付でソートされなくなるバグが存在するので注意してください。 日付でソートされなくなるとメールを探すのがかなりつらくなります。
メールをファイルに保存させるには、環境変数 MH_STORAGE に maildir と指定します。
次に環境変数 MH_MAILDIR_PATH で、保存先のディレクトリを指定します。
書き込み権限が無いとエラーになってしまうので、誰でも書き込める "/tmp" がよく使われているようです。
version: "3.8"
services:
# MailHog コンテナ
mailhog:
image: mailhog/mailhog:latest
ports:
- 18025:8025
environment:
MH_STORAGE: maildir
MH_MAILDIR_PATH: /tmp
ボリュームを使用する
メールをファイルに保存させることでコンテナ再起動時には消えなくなりますが、 それでもまだ Docker がコンテナを再作成すると消えてしまいますので、 コンテナを再作成されても消えないようにボリュームを設定しましょう。
version: "3.8"
services:
# MailHog コンテナ
mailhog:
image: mailhog/mailhog:latest
ports:
- 18025:8025
volumes:
- mailhog-data:/tmp
environment:
MH_STORAGE: maildir
MH_MAILDIR_PATH: /tmp
volumes:
mailhog-data:
PHP から MailHog コンテナにメールを送る
MailHog コンテナにメールを送る際は、MailHog コンテナの SMTP サーバーに送る必要があります。
ホスト名として docker-compose.yml で定義しているサービス名(つまり、services 項目で指定しているキー)を使用できます。
上記の例では、ホスト名として "mailhog" が使用できます。
ポート番号は 1025 番です。
PHP でメールを送る際、大きく分けて2つの方法があります。 どちらの方法を使用しているかによって設定方法が異なります。
1つ目は、PHP のメール送信関数 mail() もしくは mb_send_mail() を使用する方法です。
mail() もしくは mb_send_mail() は、
メールを直接メールサーバーに送っているわけではなく、sendmail コマンドにメールを送っています。
実際にメールを送信しているのは sendmail コマンドなのです。
つまり、sendmail コマンドから MailHog コンテナに接続するよう設定しなければなりません。
これがちょっと難しい。
そこで sendmail コマンドの代わりになるコマンド mhsendmail コマンドが用意されていますので、
これを使用すると良いでしょう。
2つ目は、PHP からソケットを開けて直接メールサーバーに接続してメールを送る方法です。 有名なフレームワークやメールライブラリなどは、だいたいこちらの方法でメールを送信しているのではないでしょうか。 こちらの場合は接続先のホストとポート番号を MailHog コンテナの SMTP サーバーに変更するだけなので特に問題はないと思います。
mhsendmail コマンドを使用する
PHP のメール送信関数 mail() もしくは mb_send_mail() を使用している場合は、
mhsendmail コマンドを使用して MailHog コンテナにメールを送信するように変更しましょう。
mhsendmail コマンドをインストールする
mhsendmail コマンドをインストールするには、Dockerfile を下記のように変更します。
なお、これを行うのは PHP が入ってるコンテナであって、MailHog コンテナではないので注意してください。
FROM php:8.2-apache # apt を最新化 RUN apt update # Go 言語 と Git をインストール # - mhsendmail を go get でインストールするために必要 RUN apt install -y golang-go RUN apt install -y git # mhsendmail をインストール RUN go get github.com/mailhog/mhsendmail \ && mv /root/go/bin/mhsendmail /usr/local/bin
php.ini の sendmail_path を変更する
mhsendmail コマンドがインストールできたら、次は PHP の設定ファイル php.ini を変更します。
php.ini の sendmail_path の値に、インストールした mhsendmail コマンドを指定します。
--smtp-addr オプションで、MailHog コンテナの SMTP サーバーのホストとポート番号を指定します。
[mail function] sendmail_path="/usr/local/bin/mhsendmail --smtp-addr=mailhog:1025"