Memo

メモ > サーバ > サービス: AWS > SES PostfixからSMTPでメールを送信

■SES PostfixからSMTPでメールを送信
サーバ内でmailコマンドを実行したり、PHPでmail関数を実行することにより、自動でSESが使用されるようにする Amazon SES と Postfix の統合 - Amazon Simple Email Service https://docs.aws.amazon.com/ja_jp/ses/latest/dg/postfix.html [AWS] Amazon SES と Postfix を連携しメールを送付する | MSeeeeN https://mseeeen.msen.jp/send-emails-by-linking-amazon-ses-and-postfix/ 【AWS】EC2インスタンスからPostfix + SESで外部へシステムメールを送信 | 電算星組 https://densan-hoshigumi.com/aws/aws-postfix-ses-send-email Amazon SESとPostfixの連携でハマったポイント - Qiita https://qiita.com/ushirog/items/bd0e890e22b01c474352 Amazon SESとpostfixの連携 - kazu22002の技術覚書 https://kazu22002.hatenablog.com/entry/2021/02/06/055536 Amazon SESのSMTPエンドポイントを試してみた | DevelopersIO https://dev.classmethod.jp/articles/sendmail-from-ses-smtpendpoint/ [AWS] Amazon SES と Postfix を連携しメールを送付する | MSeeeeN | 大阪発 IT メディア by MSEN https://mseeeen.msen.jp/send-emails-by-linking-amazon-ses-and-postfix/ Amazon SES にSPF、DKIM、DMARC設定と、サンドボックスを解除してメール送信してみた | DevelopersIO https://dev.classmethod.jp/articles/amazon-ses-set-up-spf-dkim-dmarc-and-unlocked-sandbox/ AWSからメールを送信するには?見落としがちなメール送信時の課題について解説 - ベアメールブログ https://baremail.jp/blog/2022/01/24/1891/ ■EC2の起動と設定 EC2の t2.micro を起動する ElasticIP でIPアドレスを固定しておく Route53で以下のDNSを設定しておく
refirio.net A 固定IPアドレス
言語とタイムゾーンを設定
# localectl set-locale LANG=ja_JP.UTF-8 # timedatectl set-timezone Asia/Tokyo
メールログの時差を調整
# cd /var/spool/postfix # mkdir etc # cd etc # cp /etc/localtime . # systemctl restart rsyslog # systemctl restart postfix
認証情報ファイルを作成
# vi /etc/postfix/sasl_passwd … 認証情報ファイルを新規作成
[email-smtp.ap-northeast-1.amazonaws.com]:587 AK**********JES342R7:BP**********1AlS39hD6OfyaQdm6gUzfJ3QuG6LB2Ko
# postmap hash:/etc/postfix/sasl_passwd … postmapで認証情報ファイルをハッシュ化(sasl_passwd と同じ階層に sasl_passwd.db が作成される) # chown root. /etc/postfix/sasl_passwd # chown root. /etc/postfix/sasl_passwd.db # chmod 0600 /etc/postfix/sasl_passwd # chmod 0600 /etc/postfix/sasl_passwd.db
Postfixの設定ファイルを調整
# vi /etc/postfix/main.cf
#relayhost = $mydomain #relayhost = [gateway.my.domain] #relayhost = [mailserver.isp.tld] #relayhost = uucphost #relayhost = [an.ip.add.ress] relayhost = [email-smtp.ap-northeast-1.amazonaws.com]:587 … 転送先のメールサーバ # 以下、最終行へ追記 smtp_sasl_auth_enable = yes … Postfix SMTPクライアントのSASL認証を有効にする smtp_sasl_security_options = noanonymous … Postfix SMTPクライアントで使うことが許される認証方法(今回は「匿名ログインを許可しない認証」としている) smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd … 認証情報ファイル smtp_use_tls = yes smtp_tls_security_level = encrypt … STARTTLS ESMTP機能をサポートしていれば暗号化、そうでなければ平文で送る smtp_tls_note_starttls_offer = yes smtp_tls_loglevel = 1 … TLSに関する追加ログ設定(TLSハンドシェイクと証明書の情報をログに記録する) smtp_tls_CAfile = /etc/pki/tls/certs/ca-bundle.crt … Postfix SMTPクライアント証明書を発行した認証局(CA)の証明書を持つファイル
# systemctl restart postfix … Postfixを再起動
これで、サーバ内部からメールを送信できるようになっている 一例だが、以下のようにすることで example@gmail.com にメールが送信される (SES利用開始時に「検証済みID」で登録した送信元を指定する必要があるので注意)
# yum -y install mailx # echo "本文" | mail -s "タイトル" -r info@refirio.net example@gmail.com
届いたメールのヘッダに
Received: from e234-2.smtp-out.ap-northeast-1.amazonses.com (e234-2.smtp-out.ap-northeast-1.amazonses.com. [23.251.234.2]) by mx.google.com with ESMTPS id z18-20020a170903019200b001892e5980a7si23632554plg.405.2023.01.19.19.22.20 for <example@gmail.com> (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 19 Jan 2023 19:22:20 -0800 (PST) Received-SPF: pass (google.com: domain of 01060185cd32d7e7-95598bec-cc0a-464f-bf7c-6e119af0e8a3-000000@ap-northeast-1.amazonses.com designates 23.251.234.2 as permitted sender) client-ip=23.251.234.2;
などと書かれているので、SES経由で送信できていることが確認できる また、/var/log/maillog に以下のログが記録された
Jan 20 12:22:19 ip-10-1-0-69 postfix/pickup[3733]: 3F77D458CE7: uid=0 from=<info@refirio.net> Jan 20 12:22:19 ip-10-1-0-69 postfix/cleanup[3785]: 3F77D458CE7: message-id=<63ca08eb.4XiwGj2j9Ku+rgpP%info@refirio.net> Jan 20 12:22:19 ip-10-1-0-69 postfix/qmgr[3734]: 3F77D458CE7: from=<info@refirio.net>, size=468, nrcpt=1 (queue active) Jan 20 12:22:19 ip-10-1-0-69 postfix/smtp[3787]: Trusted TLS connection established to email-smtp.ap-northeast-1.amazonaws.com[54.64.137.154]:587: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits) Jan 20 12:22:19 ip-10-1-0-69 postfix/smtp[3787]: 3F77D458CE7: to=<example@gmail.com>, relay=email-smtp.ap-northeast-1.amazonaws.com[54.64.137.154]:587, delay=0.44, delays=0.04/0.04/0.14/0.21, dsn=2.0.0, status=sent (250 Ok 01060185cd32d7e7-95598bec-cc0a-464f-bf7c-6e119af0e8a3-000000) Jan 20 12:22:19 ip-10-1-0-69 postfix/qmgr[3734]: 3F77D458CE7: removed
■外部からメールサーバのSMTPを経由して送信 ポート587を空ける 今回は実際の送信をSESに任せるので、ポート25を空ける必要は無い 正しいSMTPポートの選び方(ポート番号25、587、465、2525) https://kinsta.com/jp/blog/smtp-port/ サブミッションポートを設定する
# vi /etc/postfix/master.cf … サブミッションポートを設定(OP25Bの対応)
#submission inet n - n - - smtpd submission inet n - n - - smtpd … サブミッションポートを有効にする # -o smtpd_sasl_auth_enable=yes -o smtpd_sasl_auth_enable=yes … サブミッションポートで、SASL認証を実施(先頭のスペースの数は2つ必要みたい)
# vi /etc/sasl2/smtpd.conf
#pwcheck_method: saslauthd pwcheck_method: auxprop … SASL独自のパスワードDBを使用する
SASLの設定 - Qiita https://qiita.com/nkiw/items/cbddeaba18f8c010fb5e Postfixの設定ファイルを調整
# vi /etc/postfix/main.cf
#myhostname = virtual.domain.tld myhostname = web1.refirio.net … ホスト名(FQDN)を設定 #mydomain = domain.tld mydomain = refirio.net … ドメインを設定 #myorigin = $mydomain myorigin = $mydomain #inet_interfaces = localhost inet_interfaces = all #mydestination = $myhostname, localhost.$mydomain, localhost mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
# systemctl restart postfix … Postfixを再起動
SMTP送信ユーザの作成
# echo "パスワード" | saslpasswd2 -p -u refirio.net -c info
/etc/sasldb2 というバイナリファイルが生成されるため、所有者を調整する
# chgrp postfix /etc/sasldb2
反映されたか確認
# sasldblistusers2 info@refirio.net: userPassword … 反映されていれば、メールアドレスが表示される
これで info@refirio.net ユーザが作成されたことになる PHPMailderなどから送信テストする 一例だが、以下のようにして接続できる
// SMTPサーバ: ホスト define('SMTP_HOST', 'refirio.net'); // SMTPサーバ: メールアカウント define('SMTP_USERNAME', 'info@refirio.net'); // SMTPサーバ: メールパスワード define('SMTP_PASSWORD', 'パスワード'); // SMTPサーバ: プロトコル (ssl または tls) define('SMTP_SECURE', 'CRAM-MD5'); // SMTPサーバ: 送信ポート (ssl:465, tls:587) define('SMTP_PORT', '587');
■トラブルとその対応 外部からSMTPで接続できなかった 結論から書くと、サブミッションポートを設定し忘れていたからだった (設定しないと587番ポートに接続できないみたい) PHPMailerでメールをSTMP送信する - Qiita https://qiita.com/e__ri/items/857b12e73080019e00b5 PHPMailerで以下を指定すると、送信時の詳細なログを確認できる
$mail->SMTPDebug = 3; $mail->Debugoutput = function($str, $level) { echo "debug level $level; message: $str<br>"; };
送信完了した場合は以下のようになる
debug level 3; message: Connection: opening to refirio.net:587, timeout=300, options=array ( ) debug level 3; message: Connection: opened debug level 2; message: SERVER -> CLIENT: 220 refirio.net ESMTP unknown debug level 1; message: CLIENT -> SERVER: EHLO localhost debug level 2; message: SERVER -> CLIENT: 250-refirio.net 250-PIPELINING 250-SIZE 10485760 250-VRFY 250-ETRN 250-AUTH PLAIN LOGIN 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN debug level 1; message: CLIENT -> SERVER: AUTH LOGIN debug level 2; message: SERVER -> CLIENT: 334 VXNlcm5hbWU6 debug level 1; message: CLIENT -> SERVER: aW5mb0BjcmUudGVycmFwb3J0LWRldi5jb20= debug level 2; message: SERVER -> CLIENT: 334 UGFzc3dvcmQ6 debug level 1; message: CLIENT -> SERVER: SldqeE1xcll4OXM4 debug level 2; message: SERVER -> CLIENT: 235 2.7.0 Authentication successful debug level 1; message: CLIENT -> SERVER: MAIL FROM: debug level 2; message: SERVER -> CLIENT: 250 2.1.0 Ok debug level 1; message: CLIENT -> SERVER: RCPT TO: debug level 2; message: SERVER -> CLIENT: 250 2.1.5 Ok debug level 1; message: CLIENT -> SERVER: DATA debug level 2; message: SERVER -> CLIENT: 354 End data with . debug level 1; message: CLIENT -> SERVER: Date: Fri, 20 Jan 2023 13:38:55 +0900 debug level 1; message: CLIENT -> SERVER: To: =?UTF-8?B?44Oh44O844Or5Y+X5L+h6ICF?= debug level 1; message: CLIENT -> SERVER: From: =?UTF-8?B?44Oh44O844Or6YCB5L+h6ICF?= debug level 1; message: CLIENT -> SERVER: Subject: =?UTF-8?B?5aSW6YOoU01UUOOBi+OCieOBrumAgeS/oeODhuOCueODiA==?= debug level 1; message: CLIENT -> SERVER: Message-ID: <878c32f7524c55c24bbfa598be314438@localhost> debug level 1; message: CLIENT -> SERVER: X-Mailer: PHPMailer 5.2.19 (https://github.com/PHPMailer/PHPMailer) debug level 1; message: CLIENT -> SERVER: MIME-Version: 1.0 debug level 1; message: CLIENT -> SERVER: Content-Type: text/plain; charset=UTF-8 debug level 1; message: CLIENT -> SERVER: Content-Transfer-Encoding: base64 debug level 1; message: CLIENT -> SERVER: debug level 1; message: CLIENT -> SERVER: 44OG44K544OI44Oh44O844Or44CCDQrjgZPjgozjga/lpJbpg6hTTVRQ44GL44KJ44Gu6YCB5L+h debug level 1; message: CLIENT -> SERVER: 44OG44K544OI44Gn44GZ44CC debug level 1; message: CLIENT -> SERVER: debug level 1; message: CLIENT -> SERVER: . debug level 2; message: SERVER -> CLIENT: 250 2.0.0 Ok: queued as 0C21C456ABB debug level 1; message: CLIENT -> SERVER: QUIT debug level 2; message: SERVER -> CLIENT: 221 2.0.0 Bye debug level 3; message: Connection: closed
接続先を間違えた場合は以下のような内容が表示される
debug level 3; message: Connection: Failed to connect to server. Error number 2. "Error notice: stream_socket_client(): php_network_getaddresses: getaddrinfo failed: 〇〇〇〇〇〇〇〇〇〇 debug level 3; message: Connection: Failed to connect to server. Error number 2. "Error notice: stream_socket_client(): unable to connect to refirio.net:587 (php_network_getaddresses: getaddrinfo failed: 〇〇〇〇〇〇〇〇〇〇 ) debug level 1; message: SMTP ERROR: Failed to connect to server: php_network_getaddresses: getaddrinfo failed: 〇〇〇〇〇〇〇〇〇〇 (0) debug level 3; message: SMTP connect() failed. https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting
接続ポートを間違えた場合、サブミッションポートの設定がされていない場合は以下のような内容が表示される
debug level 3; message: Connection: Failed to connect to server. Error number 2. "Error notice: stream_socket_client(): unable to connect to refirio.net:24 (〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇 ) debug level 1; message: SMTP ERROR: Failed to connect to server: 〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇 (10060) debug level 3; message: SMTP connect() failed. https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting
存在しないメールアドレスを指定した場合、間違ったパスワードを指定した場合は以下のような内容が表示される
debug level 2; message: SERVER -> CLIENT: 535 5.7.8 Error: authentication failed: authentication failure debug level 1; message: SMTP ERROR: Password command failed: 535 5.7.8 Error: authentication failed: authentication failure debug level 3; message: SMTP Error: Could not authenticate.
プロトコルを「define('SMTP_SECURE', 'CRAM-MD5');」ではなく「define('SMTP_SECURE', 'tls');」と設定した場合は以下のような内容が表示される
debug level 1; message: CLIENT -> SERVER: STARTTLS debug level 2; message: SERVER -> CLIENT: 502 5.5.1 Error: command not implemented debug level 1; message: SMTP ERROR: STARTTLS command failed: 502 5.5.1 Error: command not implemented debug level 3; message: SMTP Error: Could not connect to SMTP host. debug level 1; message: CLIENT -> SERVER: QUIT debug level 2; message: SERVER -> CLIENT: 221 2.0.0 Bye debug level 3; message: Connection: closed
■サーバからの通知メールについて補足 サーバを運用していると、Cron実行時エラーなどがメールで送られてきたりする ただしSES+Postfixだと、送信元の問題でこういったメールが送られなくなる可能性がある (SES利用開始時に「検証済みID」で登録した送信元を指定する必要があるが、サーバがデフォルトで通知する内容を完璧に把握して送信元を調整するのは難しい) 対処方法としては 「何とかしてEC2からメールを送る」 ではなく 「ログを記録して、CloudWatchに転送して、必要に応じて警告する」 という流れにするといいみたい (EC2はデフォルトでポートが制限されているくらいなので、こういったメールを受け取れないからと言って致命的だということは無い…はず) ECSなどでオートスケーリング構成を取る場合でも同じ Webサーバは使い捨てにできる前提で構築することが好ましい サーバからの通知メールに関しては、ひとまず ・Cronの通知は無効にしない(エラーなど重大な通知を含むことがあるので) ・Cronの通知は転送設定をしなければrootのメールボックスに届くので、定期的にメールボックスの内容を確認する ・ただし定期的に手動でチェックするのは大変なので、「毎週月曜日に確認して新着メールがあれば通知」というシェルスクリプトを作る ・Anacronの通知は無効にする(原則完了報告だけなので) という方針にするか

Advertisement