AR ホームベーカリー

オイラのアウトプット用ホームベーカリー!

AWS SES を postfix 経由で利用する (mail コマンドで雑に送信できるようにする)

dev.classmethod.jp

これ。

雰囲気

雰囲気としては以下のような感じ。

mail コマンド -> 同じ環境内の postfix(sendmail) -> AWS SES -> 宛先メールボックス

/etc/postfix/main.cf
# readme_directory: The location of the Postfix README files.
#
readme_directory = /usr/share/doc/postfix-2.10.1/README_FILES
smtp_tls_note_starttls_offer = yes
smtp_tls_security_level = encrypt
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
relayhost = [email-smtp.us-east-1.amazonaws.com]:587
smtp_sasl_auth_enable = yes
smtp_use_tls = yes
smtp_tls_CAfile = /etc/ssl/certs/ca-bundle.crt
AmazonLinux2023 だと以下のようにする

smtp_tls_security_level = may日和見 TLS って言うんすかね? 調べたら出てきたけど、これは AWS SES にリレーするので暗号化強制して良いでしょう。

あとは CAfile があらかじめパス指定されているのでそれを流用する、くらい?

# The full pathname of a file containing CA certificates of root CAs
# trusted to sign either remote SMTP server certificates or intermediate CA
# certificates.
#
smtp_tls_CAfile = /etc/pki/tls/certs/ca-bundle.crt

# Use TLS if this is supported by the remote SMTP server, otherwise use
# plaintext (opportunistic TLS outbound).
#
#smtp_tls_security_level = may
meta_directory = /etc/postfix
shlib_directory = /usr/lib64/postfix

# add configuration
smtp_tls_note_starttls_offer = yes
smtp_tls_security_level = encrypt
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
relayhost = [email-smtp.us-east-1.amazonaws.com]:587
smtp_sasl_auth_enable = yes
smtp_use_tls = yes
#smtp_tls_CAfile = /etc/ssl/certs/ca-bundle.crt

master.cf のフォールバックを切る

CentOS7 世代より前くらい (SysV init の時代?) のディストリ使っている環境だと /etc/postfix/master.cf にフォールバック設定が存在する場合があるので、一応確認しておいて存在していたらコメントアウトしておいてください。

現代の postfix 的には存在していないはず。

#-o smtp_fallback_relay=

SMTP クレデンシャルの埋め込み

実際に postfix から AWS SES にリレーするときに認証する情報として SMTP クレデンシャルを埋め込みます。

これは ManagementConsole から ID 検証したときなどに、ついでに作成してダウンロードしておいてください。

# クレデンシャルを埋め込んだファイルを作る
[ec2-user@localhost postfix]$ sudo vi /etc/postfix/sasl_passwd
# postfix が解釈できるようハッシュにする
[ec2-user@localhost postfix]$ sudo postmap hash:/etc/postfix/sasl_passwd
# 権限変更する
[ec2-user@localhost postfix]$ sudo chown root:root /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
# パーミッション変更する
[ec2-user@localhost postfix]$ sudo chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
/etc/postfix/sasl_passwd

クレデンシャルは以下のように一行で書いてください。 たしか空白の改行をファイル内に入れてしまうとエラーになるはず。

先頭に [] で書いているのが接続先エンドポイントです。 これは古き良き北部ヴァージニアを指定しているやつ。 現代なら ap-northeast-1 が利用できるはず。

[email-smtp.us-east-1.amazonaws.com]:587 AKIA...:EXAMPLE...むっちゃいいクレデンシャル

送信のテスト

ここまで来たら、各種変更を反映するために systemctl restart postfix などして設定を再読み込みしてください。

その後は、昔ながらの素朴な mail コマンドを利用して、 postfix を経由して送信する。

echo "send test" | mail -s "test" -r no-reply@example.com receiver@example.com

ちなみに AWS SESではドメインさえ ID 認証できていれば、サブドメインはなにつけてもオッケーらしいのでそのあたりはサービスに利用する設定に応じて、ってやつでヨロシク〜!

qiita.com

aws ses 送信について

上記のような環境だと、 IAM の権限も SES 系は付与していないはずなので、以下のような aws ses コマンドが利用出来ないはず。 (そもそも postfix を経由しないのでメール送信テストになっていない。)

aws ses send-email \
  --from no-reply@example.jp \
  --to receiver@example.co.jp \
  --subject "test" \
  --text "send test."

ということで、本来は AWS CLI コマンドで遅れるようにすべきなんでしょうが、今回は文脈外、ってことで。

なぜこのような記事を?

これ 2015 年とかそのあたり? に構築したインスタンスで、aws-ses とか aws-rails 系の gem も未成熟で、まだ AWS SES もバージニア北部 (us-east-1) 限定だった頃の設定なんすけど、まあわりとそんな環境が多いのと、過去記事にしたはずが残ってなかったので改めて書いた、という感じです。

最近は (Docker ≒) コンテナ環境なんかで、メール送信はローカルの mail コマンド叩いたらちゃんと SMTP なり外部のサーバ参照する方がスジが良い (じゃないとコンテナ内の main.cf をビルド時にアレソレする手順が必要) ので、こういう対応はバッドノウハウになりつつある、と思うんですが一応自分の備忘録を兼ねて。

追記:2024/12/06

AmazonLinux2023 で設定する機会があったので補強しておきました。

結論から言うと、この手法は未だに利用できます。 ので、アプリケーションに認証情報を埋め込めない (mail コマンドそのまま利用する) ときなどはこのようにしましょう。