Raspberry Pi 3でDockerコンテナを使ってメールを送信する

## はじめに

LAN内から認証無しでメール送信が行えるDockerイメージを見つけたので、"[Dockerの「マルチCPUアーキテクチャ」に対応したイメージをビルドする](https://dev.classmethod.jp/articles/docker-multi-architecture-image-build/)"を参考にlinux/amd64,linux/arm64,linux/arm/v7に対応したイメージを作成しRaspberry Pi 3 Model B+上でDockerコンテナを動かしてみました。
作成したDockerイメージは [Docker Hub](https://hub.docker.com/r/revsystem/postfix/tags?page=1&ordering=last_updated)に置いています。
NASや家電製品、Raspberry Pi上のアプリケーションからPostfix Dockerコンテナを介してメールを送信できます。

[OP25B(Outbound Port 25 Blocking)](https://www.nic.ad.jp/ja/basics/terms/OP25B.html) の制約があるため、Dockerコンテナから直接相手のメールサーバーにメールを送信せず外部のSMTPサーバーをリレーして送信します。そのため、契約しているプロバイダーのSMTPサーバーの接続情報やリレーを許可しているSMTPサーバーが必要です。

Raspberry Pi 3と書いていますが、マルチCPUアーキテクチャ(linux/amd64,linux/arm64,linux/arm/v7)に対応したDockerイメージを使用するので、それらの環境でも動作すると思います。

## 参考情報
- [juanluisbaptiste/docker-postfix](https://github.com/juanluisbaptiste/docker-postfix)
- [Dockerの「マルチCPUアーキテクチャ」に対応したイメージをビルドする](https://dev.classmethod.jp/articles/docker-multi-architecture-image-build/)
- [J:COMのようなOP25Bをしていてサブミッションポート(587)をサポートしていないプロバイダでTLS(465)でメールをリレー送信する](https://www.ncaq.net/2018/12/17/19/46/36/)
- [RaspberryPiからメールを送信してみた。【Python】【Postfix】を使用。](http://raspi.seesaa.net/article/421958492.html)
- [Raspberry PiのDocker環境でAlpine Linuxイメージ（3.13以降）を使用する際の注意点](https://zenn.dev/zilch/articles/d135dde85c6ac6)
- [raspberry pi + docker + alpine で apk が動かなくなる問題](https://zenn.dev/link/comments/54d8c6196381cc) 
- [alpine 3.13, armv7 network-access seems to be broken #135](https://github.com/alpinelinux/docker-alpine/issues/135) 
- [Release Notes for Alpine 3.13.0](https://wiki.alpinelinux.org/wiki/Release_Notes_for_Alpine_3.13.0)


## リポジトリ

Dockerfileやイメージはこちらに置いています。
- https://github.com/revsystem/docker-postfix
- https://hub.docker.com/r/revsystem/postfix/

## 準備するもの

 - 契約しているプロバイダーのSMTPサーバー接続情報
 - [Raspberry Pi 3 Model B+](https://amzn.to/3dBenpo) (Raspberry Pi 4を持っていないので、Raspberry Pi 3で動作確認しています。Raspberry Pi 4でも動作すると思います。)
 - docker実行環境


## Dockerコンテナを起動
[Docker Hub](https://hub.docker.com/r/revsystem/postfix/)に置いているイメージを利用してコンテナを起動します。

```shell
docker container run -d --name postfix -p "25:25"  \
       -e SMTP_SERVER=smtp.bar.com \
       -e SMTP_USERNAME=foo@bar.com \
       -e SMTP_PASSWORD=XXXXXXXX \
       -e SERVER_HOSTNAME=helpdesk.mycompany.com \
       revsystem/postfix:latest
```


リレー先SMTPサーバの認証情報をそれぞれ指定します。`SERVER_HOSTNAME`はDockerコンテナのホスト名を指定します。
`SMTP_PORT`を指定しない場合は、デフォルトで587番ポートが設定されます。
J:COMなど587番ポートではなく465番ポートが開放されている場合は。`SMTP_PORT`に465番ポートを指定します。
例)

```shell
docker container run -d --name postfix -p "25:25"  \
       -e SMTP_SERVER=smtp.bar.com \
       -e SMTP_PORT=465
       -e SMTP_USERNAME=foo@bar.com \
       -e SMTP_PASSWORD=XXXXXXXX \
       -e SERVER_HOSTNAME=helpdesk.mycompany.com \
       revsystem/postfix:latest
```


## メールを送信

Dockerホストの25番ポートをDockerコンテナの25番ポートに転送しています。LAN内の機器からはSMTPサーバ名にDockerホストのIPアドレス、ポート番号 25を指定することでメールを送信できます。

送信テストをする場合、[RaspberryPiからメールを送信してみた。【Python】【Postfix】を使用。](http://raspi.seesaa.net/article/421958492.html) で公開されているsendMail.pyをDockerホストに置いて`to_addr`,`from_addr`を自分のメールアドレスにして実行することでテストすることができます。


## 32bit OS上でこのイメージを使用する場合
Dockerfileでalpine:3.13を指定しています｡しかし､Alpine Linux 3.13.0ではmuslというライブラリの影響で32bit OS上では動作に影響があるようです｡

[Raspberry PiのDocker環境でAlpine Linuxイメージ（3.13以降）を使用する際の注意点](https://zenn.dev/zilch/articles/d135dde85c6ac6)
> musl というライブラリがアップデートされたことにより32bit環境において時間に関する仕様変更があったようで、これを回避するためには --security-opt=seccomp=unconfined というオプション付きで docker run すれば良さそうです。

:::note warn
--security-opt=seccomp=unconfined はコンテナのセキュリティレベルが下がるようなので使用の際には注意が必要です。
:::

上記のように `--security-opt=seccomp=unconfined` オプションをつけることで影響を回避することができます｡

```shell
docker container run --security-opt=seccomp=unconfined \
       -d --name postfix -p "25:25"  \
       -e SMTP_SERVER=smtp.bar.com \
       -e SMTP_USERNAME=foo@bar.com \
       -e SMTP_PASSWORD=XXXXXXXX \
       -e SERVER_HOSTNAME=helpdesk.mycompany.com \
       revsystem/postfix:latest
```
しかし､[Release Notes for Alpine 3.13.0](https://wiki.alpinelinux.org/wiki/Release_Notes_for_Alpine_3.13.0)にこのように書かれているとおり､セキュリティレベルを下げてしまいます｡

>  but note that this will reduce the security of the host against malicious code in the container.

dockerホスト上のlibseccomp2をアップデートすることで､--security-optを使用せずに影響を回避することができます｡

[raspberry pi + docker + alpine で apk が動かなくなる問題](https://zenn.dev/link/comments/54d8c6196381cc) 

> ホスト側(raspberry pi側)の libseccomp2 を debian から公開されたものにアップデートすることで解決した。


[alpine 3.13, armv7 network-access seems to be broken #135](https://github.com/alpinelinux/docker-alpine/issues/135) を参考に､ibseccomp2_2.5.3-2_armhf.debにアップグレードすることで --security-opt を使用せずに docker runが動作しました｡

```shell
wget http://ftp.de.debian.org/debian/pool/main/libs/libseccomp/ibseccomp2_2.5.3-2_armhf.deb
dpkg -i ibseccomp2_2.5.3-2_armhf.deb
```