AWS  SES  + Ruby / Rails – メールが送信できない場合 ( aws-sdk-rails  / aws-sdk-ses )

# 結論

- 実行ユーザーの IAMに `ses:SendEmail` `ses:SendRawEmail` の権限を与える
- アクセスキーを発行してメール送信を実行する

結論としてはシンプルだが、この手順で解決した

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89618/a6d89293-b0df-0f19-ff48-24193471ed13.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89618/77eed46b-a47c-e6ab-b4a9-2cf8a3ea1141.png)

# 問題

- 「SMTP認証情報の作成」でIAMユーザーに付与される権限 `AmazonSesSendingAccess` ( `AmazonSesSendingAccess` ) では何故か送信できなかった
- 「SMTP認証情報の作成」で発行される「SMTP ユーザー名」「SMTP パスワード」を利用してもメール送信は出来なかった 

「SMTP ユーザー名」「SMTP パスワード」はいかにもAWSのアクセスキー・シークレットのような文字列なのだが別物らしい

# 公式ガイドの手順 ( Ruby で試す ) 

ApplicationMailer など Rails的なコードを作らなくても、
公式ガイドの手順でRubyでのテストが出来る

Amazon SES E メールアドレスへのメッセージの送信
https://docs.aws.amazon.com/ja_jp/sdk-for-ruby/v3/developer-guide/ses-example-send-email.html


自分の場合は便宜的にRailsでモデルのメソッドにして試した

gemには `aws-sdk-ses` を使う

```rb
require 'aws-sdk-ses' # v2: require 'aws-sdk'

sender = 'yuma.inaura@gmail.com'

recipient = 'yuma.inaura@gmail.com'

subject = 'Amazon SES test (AWS SDK for Ruby)'

htmlbody =
  '<h1>Amazon SES test (AWS SDK for Ruby)</h1>' \
  '<p>This email was sent with <a href="https://aws.amazon.com/ses/">' \
  'Amazon SES</a> using the <a href="https://aws.amazon.com/sdk-for-ruby/">' \
  'AWS SDK for Ruby</a>.'

textbody = 'This email was sent with Amazon SES using the AWS SDK for Ruby.'

encoding = 'UTF-8'

credentials = Aws::Credentials.new(
  '*****',
  '*****'
)

ses = Aws::SES::Client.new(
  region: '*****',
  credentials: credentials
)

begin
  ses.send_email(
    destination: {
      to_addresses: [
        recipient
      ]
    },
    message: {
      body: {
        html: {
          charset: encoding,
          data: htmlbody
        },
        text: {
          charset: encoding,
          data: textbody
        }
      },
      subject: {
        charset: encoding,
        data: subject
      }
    },
    source: sender
  )

  puts 'Email sent to ' + recipient

# If something goes wrong, display an error message.
rescue Aws::SES::Errors::ServiceError => e
  puts "Email not sent. Error message: #{e}"
end
```

SMTPユーザー/パスワードをアクセスキー・シークレットに指定した場合は以下エラーが起きていた

```sh
ruby aws-email.rb

Email not sent. Error message: The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
```

このコードの例はHTMLメールなので、 SendRawEmailの権限しかない場合は
権限がない場合は以下エラーが発生していた

```sh
ruby aws-email.rb

Email not sent. Error message: User `arn:aws:iam::00000000:user/ses-smtp-user.000000-000000' is not authorized to perform `ses:SendEmail' on resource `arn:aws:ses:**********:0000000000:identity/***********'
```

# Rails

Gem は aws-sdk-rails をインストールしておく
 
`gem 'aws-sdk-rails'`


```rb
require "active_support/core_ext/integer/time"

Rails.application.configure do
  # 他のメール送信方法との設定の違いはこの1行だけに収まる ( aws-sdk-rails (3.7.1) )
  config.action_mailer.delivery_method = :ses

  config.action_mailer.default_url_options = { host: 'example.com' }

  config.action_mailer.perform_deliveries = true
  config.action_mailer.perform_caching = false

  # エラーは検知するようにしておこう
  config.action_mailer.raise_delivery_errors = true
...
```


## 無理だった例

gemのバージョン ( `aws-sdk-rails (3.7.1)` ) のせいかは分からないが
次のように credeitials をいちど作って渡す方式では無理で、環境変数を利用しないとうまくメール送信できなかった

```rb
credentials = Aws::Credentials.new(
  ENV.fetch('AWS_ACCESS_KEY_ID', nil),
  ENV.fetch('AWS_SECRET_ACCESS_KEY', nil)
)

Aws::Rails.add_action_mailer_delivery_method(
  :ses,
  credentials:,
  region: 'ap-northeast-1'
)

config.action_mailer.delivery_method = :ses

```


## rails console で実行してみる

```
export AWS_ACCESS_KEY_ID="*******"
export AWS_SECRET_ACCESS_KEY="*********"
export AWS_REGION=**********

rails console
```

てきとうにメーラーを作っておいてメール送信を実行

```
irb(main):001:0> ExampleMailer.new_email.deliver_now
```

# SMTP認証情報の作成


![image](https://user-images.githubusercontent.com/13635059/230606104-37868ef2-9a4c-405d-a8d0-21d0077ebd9a.png)

SMTP認証情報の作成をするとIAMユーザーが作成され、次のように認証情報がダウンロードできる

```
ses-smtp-user.0000000000-0000000000

SMTP ユーザー名:
*****************

SMTP パスワード:
*****************
```

だがこのキーを使ってもメール発行は出来なかった


# 環境

- aws-sdk-rails (3.7.1)

# 参考

コマンドラインを使用し、Amazon SES SMTP インターフェイスを介して E メールを送信する
https://docs.aws.amazon.com/ja_jp/ses/latest/dg/send-email-smtp-client-command-line.html

コマンドひとつでメール送信する方は
環境変数にAWSのキーを設定しておく必要があり、なおかつ「SMTP ユーザー名」「SMTP パスワード」は利用できなかった

```
openssl s_client -crlf -quiet -starttls smtp -connect email-smtp.us-west-2.amazonaws.com:587
```

ユーザー名やパスワードをbase64 エンコードする方やり方では
この方法では「SMTP認証情報の作成」の「SMTP ユーザー名」「SMTP パスワード」が利用できた


```
openssl s_client -crlf -quiet -starttls smtp -connect email-smtp.us-west-2.amazonaws.com:587 < input.txt
```

# 検証済みメールアドレスにしかメール送信できない

```
Email address is not verified. The following identities failed the check in region *****
(Aws::SES::Errors::MessageRejected)
```

送信元に検証済みメールアドレスしか指定できないのは分かるが、送信先にも指定できないとはどういうことだ？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89618/6359097e-ee35-bf34-6ee9-eb20bcdb03e8.png)


と思ったらサンドボックス環境だとそういう動作になるようだ

AmazonSESで登録したメールアドレスにしかメールが送れない理由
https://blog.framinal.life/entry/2018/08/24/094009

Amazon SES サンドボックス外への移動

>E メールの送信先は、検証済み E メールアドレスおよびドメイン、または Amazon SES メールボックスシミュレーターに制限されます。
https://docs.aws.amazon.com/ja_jp/ses/latest/dg/request-production-access.html

# ECSでは

RailsにWebアクセスした時にメール送信する場合、
タスク定義のタスクロールにメール送信のポリシー ( `ses:SendEmail` `ses:SendRawEmail` )をつければ良いようだ
(タスク実行ロールではなく)

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura