AWS EC2+Postfix+SESでEC2インスタンスからメール送信をする

はじめに

AWS EC2にPostfixをインストールし、AWS SESを利用してEC2からメールを送るということをやったので記録しておく。

動機

EC2からのメール送信は、下記のようにポート25に制限がかかっている。

そのため、制限解除や他の解決策が必要になっている。

解決策としては、

  • EC2からのメール送信の利用制限を解除する
  • SESを利用する(メール送信サービスを利用)

の2点がある。

1点目の制限解除は、利用制限解除をするにあたってスパムメール対策の施策をAWSに連絡しなければならない。
その結果、利用が可能かどうかについてAWS側で判断し制限の解除が実施されることになる。

2点目は、外部のメール送信サービスを利用する。(今回はSESを想定する)
SESを利用することで、信頼度やSPFおよびDKIMを設定することになった際に SESの方が柔軟に対応できると考えたため、今回はSESを利用する方を選択した。
※外部のメール送信サービス、例えばSendGrid等でも良いが、AWS内で完結させることを考えSESを利用することにする。

費用について

無料利用枠は 3000件かつ期間は最初の1年のみとなっている。
以降は 1000件ごとに0.1USDかかる。

準備

※既に使用するEC2インスタンスがあればこの手順はスキップして良い。

EC2のインスタンスの作成

  1. サービスより「EC2」を選択する。
  2. ナビゲーション ペインから「インスタンス」→「インスタンス」を選択する。
  3. 「インスタンスを起動」を選択する。
  4. 適当に設定する、今回は下記のように設定。
名前アーキテクチャインスタンスタイプストレージAMI
test64ビット(Arm)t4g.nano8GBAmazonLinux2023

手順

SESの設定1 (初期設定~ドメインの追加)

  1. AWSのコンソールにログインをする

  2. サービスより「Amazon Simple Email Service」を選択する。(SESを選択する)
    setting-ses-1

  3. ナビゲーションペインより、「設定を始める」を選択する。
    setting-ses-2

  4. ステップ1のメールアドレスを追加をする。
    ※検証リンクのために使用するメールアドレスのため、自分が所有しているメールアドレスを入力する。

  5. ステップ2「送信ドメインを追加」をする。
    ※EC2→Postfix→SESでメールを送信するので、送信元メールアドレスのドメインを入力する。(ここでは、自サイトのk-bushi.comとする)
    setting-ses-3

  6. ステップ3「SES を確認して、使用を開始する」にて、メールアドレスとドメインを確認し、「Get started」を選択する。 setting-ses-4

  7. ステップ1で入力したメールアドレスに検証メールが送信されるので確認をする。 setting-ses-5
    上記の表題のようなメールが受信できていたので、メールの内容をよく読み、メール内のリンクをクリックする。

  8. ドメインの追加完了 setting-ses-6

ここまでで、AWSコンソールの「SES」のページにて、ナビゲーションペインより「検証済みID」を確認する。
setting-ses-7
すると、k-bushi.comは「検証保留中」、先程追加したメールアドレスは「検証済み」となっている。
次のステップでは、送信ドメインの検証を行う。

SESの設定2 (送信元ドメインの検証)

  1. ナビゲーションペインより「検証済みID」を選択し、「検証済みID」の一覧に遷移する。

  2. 一覧から追加したドメイン(ここでは k-bushi.com )を選択する。

  3. 表示された CNAMEレコードをDNSのレコードに追加する。
    ※k-bushi.comはCloudflareで管理しているが、ここではその手順の記述は割愛する。
    CloudflareではDNSレコード設定でProxyを設定できるが、オフにしないと設定できないことに注意。
    setting-ses2-1
    setting-ses2-2
    Cloudflareで設定が完了した。

  4. 設定が正しいかどうかについて確認をする。
    下記のサイトを利用し、ホスト名、オプション(CNAMEを選択) を入力し、dig実行を行う。
    https://www.cman.jp/network/support/nslookup.html
    ちゃんとできれば、ANSWER SECTION:に登録したCNAMEが結果として返ってくる。
    問題なく設定されているのであれば、検証保留中のステータスが変わるまで少し待ってみる。
    ※大体10分くらい待ったら検証済になっていた。

  5. ナビゲーションペインより「検証済みID」を選択し、「検証済みID」の一覧に遷移し、対象のドメインが検証済になっていることを確認する。 setting-ses2-3

これにて、このステップは完了した。
次のステップでは、テストメールの送信を行い動作を確認する。

※補足: DKIM setup SUCCESSのメールが受信されていた。(To: AWSの管理者メールアドレス)
setting-ses2-4

SESの設定3 (テストメールの送信)

  1. ナビゲーションペインより「検証済みID」を選択し、「検証済みID」の一覧に遷移する。

  2. 検証済みとなっている対象のドメインを選択する。

  3. 右上にある「テストEメールの送信」を選択する。
    setting-ses3-1

  4. 設定を行い、Eメールの送信を行う。

    Eメール形式From-addressシナリオカスタム受信者件名本文設定セット
    フォーマット済みno-reply⭐️k-bushi.comカスタム[検証済みのメールアドレス](省略)(省略)my-first-configuration-set

※SESがサンドボックス環境内のため、検証済みのメールアドレスのみにしか送れないことに注意。
現状では、SESの設定1 で追加したメールアドレスにしか送れない
setting-ses3-2

  1. メールが正しく送信されたかを確認する。
    setting-ses3-3
    余談だが、gmailの場合にSPF, DKIM, DMARCを確認するには下記で確認できる。
    受信したメールを表示→メッセージのソースを表示
    setting-ses3-4

これにて、このステップは完了。 最後のステップでは、Postfixから送信するためのSMTP認証情報を取得する。

SESの設定4(SMTP認証情報の取得)

  1. ナビゲーションペインより「SMTP設定」を選択する。

  2. 右上の「SMTP認証情報の作成」を選択する。 setting-ses4-1 ※IAMユーザーの作成画面に遷移する。

  3. ステップ1「ユーザーの詳細を指定」では特に設定を変更せずに「ユーザーの作成」を選択する。 setting-ses4-2

  4. ユーザー作成後に、SMTP認証情報が表示されるので「.csvファイルをダウンロード」で認証情報を取得しておく。 ダウンロード完了後に、SESコンソールに戻るを選択する。 setting-ses4-3

これでSESの設定はすべて完了した。 次のステップから、EC2の設定になる。

EC2の設定1 (Postfixをインストール)

  1. AmazonLinux2023にて postfix をインストールする。
sudo dnf install postfix

下記がインストールされる。

Last metadata expiration check: 0:01:25 ago on Sat Jan 13 00:45:29 2024.
Dependencies resolved.
=============================================================================================================================================================================================================================================
 Package                                             Architecture                                        Version                                                               Repository                                               Size
=============================================================================================================================================================================================================================================
Installing:
 postfix                                             aarch64                                             2:3.7.2-4.amzn2023.0.4                                                amazonlinux                                             1.5 M
Installing dependencies:
 libicu                                              aarch64                                             67.1-7.amzn2023.0.3                                                   amazonlinux                                             9.5 M

Transaction Summary
=============================================================================================================================================================================================================================================
Install  2 Packages

Total download size: 11 M
Installed size: 45 M
Is this ok [y/N]:
  1. バージョンの確認
sudo postconf | grep mail_version

mail_version = 3.7.2
milter_macro_v = $mail_name $mail_version

EC2の設定2 (PostfixからSESにリレーをする設定)

  1. main.cf のバックアップを取得する。
sudo cp -p /etc/postfix/main.cf /etc/postfix/main.cf.20240113
  1. main.cf 内を下記のように修正する。
sudo vim /etc/postfix/main.cf
[ec2-user@ip-172-31-19-47 ~]$ diff -u /etc/postfix/main.cf.20240113 /etc/postfix/main.cf
--- /etc/postfix/main.cf.20240113       2023-02-01 22:11:00.000000000 +0000
+++ /etc/postfix/main.cf        2024-01-13 01:12:46.413534962 +0000
@@ -97,6 +97,7 @@
 #
 #myhostname = host.domain.tld
 #myhostname = virtual.domain.tld
+myhostname = k-bushi.com
 
 # The mydomain parameter specifies the local internet domain name.
 # The default is to use $myhostname minus the first component.
@@ -104,6 +105,7 @@
 # parameters.
 #
 #mydomain = domain.tld
+mydomain = $myhostname
 
 # SENDING MAIL
 # 
@@ -184,7 +186,7 @@
 #
 # See also below, section "REJECTING MAIL FOR UNKNOWN LOCAL USERS".
 #
-mydestination = $myhostname, localhost.$mydomain, localhost
+mydestination = localhost.$mydomain, localhost
 #mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
 #mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain,
 #      mail.$mydomain, www.$mydomain, ftp.$mydomain
@@ -274,7 +276,7 @@
 # 
 #mynetworks_style = class
 #mynetworks_style = subnet
-#mynetworks_style = host
+mynetworks_style = host
 
 # Alternatively, you can specify the mynetworks list by hand, in
 # which case Postfix ignores the mynetworks_style setting.
@@ -321,7 +323,7 @@
 # list this system as their primary or backup MX host. See the
 # permit_mx_backup restriction description in postconf(5).
 #
-#relay_domains = 
+relay_domains = $mydestination
 
 # INTERNET OR INTRANET
 
@@ -343,6 +345,7 @@
 #relayhost = [mailserver.isp.tld]
 #relayhost = uucphost
 #relayhost = [an.ip.add.ress]
+relayhost = [email-smtp.ap-northeast-1.amazonaws.com]:587
 
 # REJECTING UNKNOWN RELAY USERS
 #
@@ -737,11 +740,22 @@
 # trusted to sign either remote SMTP server certificates or intermediate CA
 # certificates.
 #
-smtp_tls_CAfile = /etc/pki/tls/certs/ca-bundle.crt
+smtp_tls_CAfile = /etc/ssl/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
+#smtp_tls_security_level = may
 shlib_directory = /usr/lib64/postfix
 meta_directory = /etc/postfix
+
+# hide mail client name and version.
+smtpd_banner = $myhostname ESMTP unknown
+
+# for SMTP Auth
+smtp_sasl_auth_enable = yes
+smtp_sasl_security_options = noanonymous
+smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
+smtp_use_tls = yes
+smtp_tls_security_level = encrypt
+smtp_tls_note_starttls_offer = yes

※relayhostのリージョンに注意すること。

  1. sasl_passwdの編集
sudo vim /etc/postfix/sasl_passwd

先程取得したSMTPの認証情報を利用する。 SMTPUSERNAME:SMTPPASSWORD には、 ユーザ名:パスワードの形式で入力する。

[email-smtp.ap-northeast-1.amazonaws.com]:587 SMTPUSERNAME:SMTPPASSWORD

※SESのリージョンに注意すること。

  1. postmapで*.dbファイルの作成
sudo postmap hash:/etc/postfix/sasl_passwd
  1. 所有権を変更する。
sudo chown root:root /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
sudo chmod 0600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
  1. CA-bundleの位置を編集する
sudo postconf -e 'smtp_tls_CAfile = /etc/ssl/certs/ca-bundle.crt'
  1. Postfixの再起動
sudo systemctl restart postfix

EC2の設定3 (動作確認)

  1. sendmailコマンドにて検証済みドメインのメールアドレスに送信する。
sendmail -f no-reply@k-bushi.com [検証済みのメールアドレス]
From: from postfix relay ses <no-reply@k-bushi.com>
Subject: Amazon SES Test Subject
This message was sent from ses via postfix in ec2
second line
third line
.
  1. 受信できていることを確認する。
setting-ec2-3-1

本番稼働アクセスのリクエスト

サンドボックス環境内での設定および動作確認は問題なかったのであれば、本番稼働アクセスのリクエストを行い、検証済みメールアドレス以外にも送信できるようにAWSにリクエストを行う必要がある。

  1. ナビゲーションペインより「アカウントダッシュボード」を選択する。 production-request-1

  2. 「Amazon SES アカウントは以下のサンドボックスにあります」と記載がある箇所の、「設定を始めるページを表示」を選択する。
    production-request-2

  3. 本番稼働の理由やサイトURLを入力し、リクエストを送信する。 production-request-3

  4. レビュー中になるので待つ。
    ※この内容だとだめだったみたいで指摘を受けた。
    production-request-4

  5. 理由を説明して返信済み。
    ※現在待ちの状態。
    31時間後くらいに返信が来て本番稼働のリクエストが承認された。土日だけどサポートが早かった! production-request-5

  6. 検証済みメールアドレス以外にもEC2から送ってみる。
    sendmail コマンドは前の手順で使用したものと同じ。
    結果↓
    production-request-6

以上にて、EC2->Postfix->SESでメール送信できるようになった。

参考

おわりに

AWS EC2からそのままメールを送信するということが簡単にはできないので、SESを利用する方法をとった。
SESでも本番稼働のリクエストはしっかり説明できないと今回のようにrejectされてしまうので注意が必要。
世界のスパムメール数は年々多くなっているので、これの影響なのかと思われる。
多くのスパムメールにAWS SESが使われてしまったら、ドメインごと拒否されるようになって信頼がなくなってしまうので慎重になっているのかなと想像している。

Hugo で構築されています。
テーマ StackJimmy によって設計されています。