東京リージョンのAWS SESで、SMTP認証を使ってメール送信をする

# TL;DR

* 周知のとおり（？）、AWS SESが東京リージョンで使えるようになりました
* 東京リージョンでSMTP認証情報を使う時のパスワードはシークレットアクセスキーを変換して使います
    * 米国東部（バージニア北部）リージョンなら署名バージョン2で変換
    * アジアパシフィック （東京）リージョンなら署名バージョン4で変換

[Amazon SES　東京リージョン対応のお知らせ](https://aws.amazon.com/jp/blogs/news/amazon-ses-tokyo/)


# Amazon SESとSMTP

Amazon SESでSMTP送信を行うためには、SMTP認証用のIAMユーザーを作成する必要があります。

[Amazon SES SMTP 認証情報の取得](https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/smtp-credentials.html)

SMTP認証で使うユーザー名とパスワードは、作成したIAMユーザーのアクセスキーID、シークレットアクセスキーを変換したものになります。

ここで作成したIAMユーザーを使い、smtp-cliを使ってメール送信を行ってみたいと思います。

[smtp-cli](https://github.com/mludvig/smtp-cli)

この時、パスワードに使用する情報に注意します。

IAMユーザーは、Terraformで作成します。


# 環境

今回使用した環境は、こちらです。

```shell
$ terraform version
Terraform v0.12.28
+ provider.aws v2.70.0

$ ./smtp-cli --version
smtp-cli version 3.10
```

AWSのクレデンシャルは、環境変数で指定します。

```shell
export AWS_ACCESS_KEY_ID=xxxxx
export AWS_SECRET_ACCESS_KEY=xxxxx
export AWS_DEFAULT_REGION=ap-northeast-1
```


# IAMユーザーの作成

最初に、SMTP認証用のIAMユーザーを作成します。

`main.tf`

```go
terraform {
  required_version = "=  0.12.28"
}

provider "aws" {
  version = "2.70.0"
}

resource "aws_iam_user" "ses_smtp" {
  name = "SesSmtpUser"
}

resource "aws_iam_user_policy" "ses_smtp_user" {
  name   = "SesSmtpPolicy"
  user   = aws_iam_user.ses_smtp.name
  policy = <<JSON
{
  "Version":"2012-10-17",
  "Statement":[
    {
      "Effect":"Allow",
      "Action":[
        "ses:SendEmail",
        "ses:SendRawEmail"
      ],
      "Resource":"*"
    }
  ]
}
JSON
}

resource "aws_iam_access_key" "ses_smtp_key" {
  user = aws_iam_user.ses_smtp.name
}

output "aws_iam_access_key" {
  value     = aws_iam_access_key.ses_smtp_key.id
  sensitive = true
}

output "aws_iam_secret" {
  value     = aws_iam_access_key.ses_smtp_key.secret
  sensitive = true
}

output "aws_iam_smtp_password_v2" {
  value     = aws_iam_access_key.ses_smtp_key.ses_smtp_password
  sensitive = true
}

output "aws_iam_smtp_password_v4" {
  value     = aws_iam_access_key.ses_smtp_key.ses_smtp_password_v4
  sensitive = true
}
```

[Resource: aws_iam_access_key](https://www.terraform.io/docs/providers/aws/r/iam_access_key.html)

Terraformを使ってIAMユーザーを作り、アクセスキーIDを作成すると、SMTP認証用のパスワードが得られるので、こちらを使用しましょう。

```shell
$ terraform apply
```

Outputに関しては、`terraform.tfstate`を参照…。


# メールアドレスの検証とメール送信を行う

続いて、Amazon SESのメールアドレス検証を行い、サンドボックス状態にします。

[E メールアドレスの検証](https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/verify-email-addresses-procedure.html)


## 米国東部（バージニア北部）リージョンで試す

まず最初に、`us-east-1`リージョンで試します。

メールアドレスの検証。

```shell
$ aws ses verify-email-identity --email-address [メールアドレス] --region us-east-1
```

受信したメールのリンクにアクセスして、検証を完了しましょう。

続いて、`us-east-1`リージョンのSMTPサーバー（`email-smtp.us-east-1.amazonaws.com:587`）に対してメール送信。

```shell
$ ./smtp-cli --host email-smtp.us-east-1.amazonaws.com:587 --enable-auth --user [アクセスキーID] --from [Verifyしたメールアドレス] --to [Verifyしたメールアドレス] --subject 'test mail' --body-plain 'Hello SES!'
```

この時、署名バージョン4を使って変換したパスワードを使うと

```go
output "aws_iam_smtp_password_v4" {
  value     = aws_iam_access_key.ses_smtp_key.ses_smtp_password_v4
  sensitive = true
}
```

認証に失敗します。

```shell
Enter password for [アクセスキーID]@email-smtp.us-east-1.amazonaws.com:587 : 
AUTH LOGIN failed: 535 Authentication Credentials Invalid
```

署名バージョン2を使って変換したパスワードを使うと

```go
output "aws_iam_smtp_password_v2" {
  value     = aws_iam_access_key.ses_smtp_key.ses_smtp_password
  sensitive = true
}
```

メール送信がうまくいきます。

リソース`aws_iam_access_key`のAttributeの説明を見ると

[Resource: aws_iam_access_key](https://www.terraform.io/docs/providers/aws/r/iam_access_key.html)

署名バージョン2は非推奨なので、署名バージョン4なのかな？と思ったのですが、そうでもないようですね。

> ses_smtp_password - DEPRECATED The secret access key converted into an SES SMTP password by applying AWS's SigV2 conversion algorithm

> ses_smtp_password_v4 - The secret access key converted into an SES SMTP password by applying AWS's documented Sigv4 conversion algorithm. As SigV4 is region specific, valid Provider regions are ap-south-1, ap-southeast-2, eu-central-1, eu-west-1, us-east-1 and us-west-2. See current AWS SES regions

署名バージョン4は、使えるリージョンが限られているみたいですし。


## アジアパシフィック （東京）リージョンで試す

続いて、`ap-northeast-1`リージョンで試します。

まずは、メールアドレスの検証。こちらもあらためて`ap-northeast-1`リージョンで行いましょう。

```shell
$ aws ses verify-email-identity --email-address [メールアドレス] --region ap-northeast-1
```

送信されてきたメールを確認したら、今度はSMTPサーバー（`email-smtp.ap-northeast-1.amazonaws.com:587`）に対してメール送信を行います。

```shell
$ ./smtp-cli --host email-smtp.ap-northeast-1.amazonaws.com:587 --enable-auth --user [アクセスキーID] --from [Verifyしたメールアドレス] --to [Verifyしたメールアドレス] --subject 'test mail' --body-plain 'Hello SES!'
```

こちらは、署名バージョン2を使って変換したパスワードを使うと

```go
output "aws_iam_smtp_password_v2" {
  value     = aws_iam_access_key.ses_smtp_key.ses_smtp_password
  sensitive = true
}
```

認証に失敗します。

```shell
Enter password for [アクセスキーID]@email-smtp.ap-northeast-1.amazonaws.com:587 : 
AUTH LOGIN failed: 535 Authentication Credentials Invalid
```

署名バージョン4を使って変換したパスワードを使うと

```go
output "aws_iam_smtp_password_v4" {
  value     = aws_iam_access_key.ses_smtp_key.ses_smtp_password_v4
  sensitive = true
}
```

メール送信に成功します。

使うリージョンでSMTP認証時のパスワード形式が違うみたいなので、覚えておきましょう…。


# 参考

[署名バージョン 4 署名プロセス](https://docs.aws.amazon.com/ja_jp/general/latest/gr/signature-version-4.html)

[署名バージョン 2 の署名プロセス](https://docs.aws.amazon.com/ja_jp/general/latest/gr/signature-version-2.html)