Amazon SESへqmailからSMTPリレーする


こんにちは。[株式会社シーズ](https://www.seeds-std.co.jp/)の原口と申します。
この記事は、[Japan APN Ambassadors Advent Calendar 2021](https://qiita.com/advent-calendar/2021/japan-apn-ambassador) の 7日目のエントリです。
APN Ambassadorって何？と言う方は、[APN Ambassadorsってなんだ？2021年度版](https://qiita.com/keizoa/items/8c2c68783c49e609f78a)をご参照ください。

今年は弊社はデータセンタ閉鎖を行い、100台弱の既存オンプレミスサーバをAWSへ移行しました。私的にはMigration of the yearです。
そんな大きなプロジェクトに関するお話もしたかったのですが、AWS移行の大きなカテゴリーであるメール、、、その中でもとりわけqmailについてフォーカスしたニッチな技術記事になります。
今回のAWS移行においてはqmailからSES利用がうまくできなかったのでPostfixへ変更していたのですが、どうしても敗北感がありもやもやしてたので、こちらを再トライしてみました。

## Amazon SES使ってますかー！

AWSでメールを送信するならAmazon SESですよね。
アカウントレベルのサプレッションリストがデフォルトで有効となりバウンスレートや苦情レートの上昇による利用停止措置も受けにくくなり、ますます使いやすくなりました。

Amazon SESはAPIによるメール送信も行えるためサーバレスやコンテナのような環境ではアプリケーションから直接利用する事も一般的となってきているのではないかと思います。
しかしながら、既存システムからのSES利用にあたってはアプリケーションの修正なく、EC2の既存MTAから気軽にメールを送りたいという需要は意外と多いのではないでしょうか。

## Amazon SES を既存のMTA(メール転送エージェント)と統合する

すでにMTAを利用した既存メールサーバーがある場合、Amazon SESのSMTPエンドポイントを利用したメール送信を行う事ができます。
既存MTAを使ってSESから送信する最大のメリットは、Linuxコマンドであるmailコマンドやsendmailコマンドを使ったメール送信が行える事です。これによって既存アプリケーションの改修なくAmazon SESを利用する事ができます。お手軽ですね。

これはMTAからSESへSMTPリレー設定を行う事で実現します。
主要なMTAであるPostfixなどは設定ファイルをちょちょっと設定するだけでSESからのメール送信が可能となります。

(参考)Amazon SES を既存の E メールサーバーと統合する
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/send-email-smtp-existing-server.html

AWS公式ドキュメントでは主要なMTAにおけるSESへのSMTPリレー手順が記載されていますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42887/4c168e32-e5b4-ab22-e28a-3c14069558da.png)

Postfix、Sendmail、IIS SMTP、Exim、、、、あれ！**qmailがない！！**
かつては主要なMTAの一つであったqmail。。qmailからSESを使いたいという需要は少なからずあるのではないでしょうか？
という事で古きMTAであるqmailからのSESへのSMTPリレーを試してみました。

## qmailからのAmazon SESへのSMTPリレー

要はAmazon SESをqmailからのスマートホスト(smarthost)として利用したいという形となります。
Amazon SESのSMTPエンドポイントの利用にあたっては以下の3つの要件を満たすMTAである必要があります。

・SMTPリレーを介した送信をサポートしている事
・SMTPリレー時にSMTP認証(AUTH LOGIN)ができる事
・接続がTLSで暗号化されている事

こちらの後半2点においてqmailは対応していません！
これらの課題をqmailの伝統芸であるパッチによって解決していきます。

## それぞれ解決していく

前提としてqmailがインストールされているものとします。

### SMTPリレーを介した送信をサポートしている事

こちらはqmailはデフォルトで対応しています。
/var/qmail/control/smtproutes にリレー先を以下のように記述する事でqmailが全てのメール送信をSESへリレーしてくれます。

```
:email-smtp.ap-northeast-1.amazonaws.com:587
```
もちろんこれだけでは認証情報がないのでリレーできません


### SMTPリレー時にSMTP認証(AUTH LOGIN)ができる事

こちらはqmailはデフォルトでは対応していないため、以下の2点のパッチを導入します。

・qmail-smtpd-auth
・qmail-remote-auth

https://tomclegg.ca/qmail/

**qmail-smtpd-auth**
qmailをSMTP-AUTHに対応するパッチです。qmail側への接続へのSMTP-AUTHを行うものなので本来は不要なのですが、後述の qmail-remote-authパッチがこちらの導入が前提となっているため導入します。

```
cd /path/to/qmail-1.03/
wget http://tomclegg.net/qmail/qmail-smtpd-auth-0.31.tar.gz
tar xvfz qmail-smtpd-auth-0.31.tar.gz
cd qmail-smtpd-auth-0.31
cp *.* ../
cd ../
patch < auth.patch
```

**qmail-remote-auth**
こちらがお目当てのパッチです。SMTP認証をqmail-remoteに追加して、認証がリレーサーバを介してメール送信を可能とします。

```
cd /path/to/qmail-1.03/
wget http://tomclegg.net/qmail/qmail-remote-auth.patch
patch < qmail-remote-auth.patch
```

こちらの2点のパッチを導入しましたらqmailを再コンパイルします

```
make
make setup
make check
```

この状態で/var/qmail/control/smtproutesへ以下のように記述する事で、認証を行なってSMTPリレーが可能となります:grin:

```
:email-smtp.ap-northeast-1.amazonaws.com:587 アクセスキー シークレットキー
```

### 接続がTLSで暗号化されている事

こちらを対応するようなqmailパッチは存在しません。
qmail本体では対応できないとするとどうするか、、、そう思った時に思いつきました。
Amazon EFSや昔のSESではTLS接続するのにstunnelを使ってたな、、、と。
SESに対するTLSの処理はstunnelで行い、stunnnelにはTLS無しで接続させるという形でやってみます。

以下のコマンドでインストール (* Amazon Linux 2を想定しています)

```
yum install stunnel
```

設定ファイルを作成します

vi /etc/stunnel/stunnel.conf

```
pid = /var/run/stunnel.pid
output = /var/log/stunnel.log
CAfile = /etc/pki/tls/certs/ca-bundle.crt
[smtps]
accept = 10465
client = yes
connect = email-smtp.ap-northeast-1.amazonaws.com:465
sslVersion = TLSv1.2
options = NO_SSLv2
options = NO_SSLv3
options = NO_TLSv1
options = NO_TLSv1.1
```

起動

```
stunnel /etc/stunnel/stunnel.conf
```

ローカルの10465ポートへ非暗号化通信であるtelnetで接続するとSESが返答してくれている事がわかります。

```
[root@ip-172-30-1-72 ~]# telnet localhost 10465
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 email-smtp.amazonaws.com ESMTP SimpleEmailService-d-1ZCC87W6E mzCQQsfuXhBCUdqrKvHK
451 4.4.2 Timeout waiting for data from client.
```

ここまでくれば/var/qmail/control/smtproutesを以下のようにstunnelへ向ける事でqmailからSESのSMTPエンドポイントへのリレーが可能となります！

```
:127.0.0.1:10465 アクセスキー シークレットキー
```

実際にqmailでメール送信を行なってみてログを確認します。

```
@4000000061aa3a480a3fae1c info msg 2689857: bytes 374 from <root@seeds-std.co.jp> qp 7246 uid 0
@4000000061aa3a480a676de4 starting delivery 31: msg 2689857 to remote haraguchi@seeds-std.co.jp
@4000000061aa3a480a67816c status: local 0/60 remote 1/60
@4000000061aa3a481b1f9c74 delivery 31: success: 127.0.0.1_accepted_message./Remote_host_said:_250_Ok_0106017d80f38322-fdd0c104-4c96-461f-a479-135c3bb4034d-000000/
@4000000061aa3a481b20ec64 status: local 0/60 remote 0/60
@4000000061aa3a481b214e0c end msg 2689857
```

ばっちりですね。

## まとめ

今回はとりあえずできるかどうかという検証でしたので、実際のプロダクション環境では負荷試験や運用実績が欲しいところですが、ひとまずの足掛かりとしていかがでしょうか？
もし既存環境がqmailでそこからのSES利用ができずお困りの方は是非ご参考いただければ幸いです。

久しぶりにqmailへのパッチ当てたりとか楽しかったです:laughing: