Django-SESとAmazon SESでメール運用しようとした時に詰みまくった話(最速の運用手順も紹介)

## はじめに
これは[Django Advent Calendar 2019](https://qiita.com/advent-calendar/2019/django) 24日目の記事になります。
クリスマスイブでもDjangoについて考えている自分に誇りを持って、記事を書きました。笑

まだまだ初心者の身ですが、Djangoを勉強していて、ある点で何時間も詰まりました(少し新しい詰まり方？)。参考文献が英語にしてもジャストな記事が無かったので、『他の方がここで躓いて欲しくない』という気持ちで、この記事を書くに至りました。

## 今回の記事の構成
最初は読者層を広げるためにDjango-sesとAmazon-SESをつかってメール配信を行える最速の手順をご紹介します(｡･_･｡)
その次に、一応今回の本題である詰まった部分を紹介したいと考えています！

## 対象読者
タイトル通りなのですが、『**django-ses**と**Amazon SES**(Amazon Simple Email Service)を利用して、メールを配信しようと思っている方』へ向けての記事です。

## 開発環境
- Python:3.8.0
- Django:2.2.9(※Django:3.0で環境構築すると詰まります。[記事下へジャンプ](#今回の記事の本題に入ります詰みまくった話))
- Django-ses:0.8.13
- boto3:1.10.44

## 今回の目標を確認
今回は『AmazonSESとDjango-SESを用いてsend_mail出来れば目標達成！』ということにします。
※環境を構築するのが目標以前に難しすぎるので、環境構築にDockerを使用することをお許しください。

プログラムの完成形(AmazonSESのKEY設定でsettingsをイジる必要アリ)は[コチラのGitHub](https://github.com/Hirochon/django-ses-sample)にあげておきました。

## プログラムを作成していく
### Docker系のファイル
まずはサラッとDocker系のファイルを載せておきます。
以下のファイルをdocker-ses-sampleディレクトリ下に作成してください。

```docker:dockerfile
FROM python:3

ENV PYTHONUNBUFFERED 1

RUN mkdir /code
WORKDIR /code

COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/
```

```docker-compose:docker-compose.yml
version: "3"
services: 
    django-ses-sample:
        build: .
        volumes: 
            - .:/code
        ports: 
            - "8000:8000"
        command: python manage.py runserver 0.0.0.0:8000
```

次にインストールするパッケージ達一覧です。

```text:requirements.txt
Django==2.2.9
boto3==1.10.44
django-ses==0.8.13
```

↓現在のディレクトリこんな感じ↓

```directly:作業ディレクトリ
django-ses-sample
　          ├ dockerfile
　          ├ docker-compose.yml
　          └ requirements.txt
```

ここから一気にstartprojectまでしてしまします。
まずdockerをいじれるCLIを開いてください。(僕はUbuntu18.04LTSのCLI使ってます)

次に作業ディレクトリまで移動します。

```CLI:dockerがイジれるCLI
~/$ cd django-ses-sample
~/django-ses-sample$ docker-compose run --rm django-ses-sample django-admin startproject config .
```

これによってビルドついでにstartprojectまでいけるので、楽です。
そしてこんな表示が来たら成功です。

```cli:dockerがイジれるCLI
Successfully tagged djangosessample_django-ses-sample:latest
```

そしてdjango-ses-sample下にstartprojectされているのが確認できたら、次へ進みましょう！

### Django系のファイル
つぎにstartprojectによって作成されたconfig内のsettings.pyをいじっていきます。
settings.py内にINSTALLED_APPSという欄があるので、コチラにdjango_sesを追加していきます。

```python:settings.py
     :
INSTALLED_APPS = [
         :
    'django_ses', #追加した
]
```

次に一番下までスクロールして、新たに以下のプログラムを追加してください。

```python:settings.py
    :
# AWS settings 
AWS_ACCESS_KEY_ID = 'AKI***********'       # アクセスキーID
AWS_SECRET_ACCESS_KEY = '****************************'     # シークレットアクセスキー

# Email settings
EMAIL_BACKEND = 'django_ses.SESBackend'         # これは必須
DEFAULT_FROM_EMAIL = SERVER_EMAIL = '**** <****@******>' #送信元のユーザ名とメールアドレス(例:'飛鳥 <asuka@nogi.com>')
```

このようにアクセスキーIDとシークレットアクセスキーを設定する必要があります。これは次の章でAWSにて作成するので今は空欄でOKです。
またEMAIL_BACKENDにてメール配信の設定をしています。ここでDjango-SESを使うことを宣言しています。
最後の行は送信側の情報を置いておきます。

この時点でのプログラムは[コチラのGitHub](https://github.com/Hirochon/django-ses-sample)にて置いておきました。

## AWSへ色々と設定しに行く
### Amazon SESの登録手順
*制限解除を行っていないアカウント にて、AmazonSESを使用するには送信するメールアドレスと受け取るメールアドレスを登録しておく必要があります。
[*1 Amazon SES Documentaition](https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/limits.html)

1. まずAWSのアカウントを用意してください。

2. そしてサインインができたら、サービスにてSES(Simple Email Service)を入力してそのページへ飛んでください。

3. ここで恐らく標準のリージョンを東京としていた人は、リージョンの選択をさせられるので、**必ず米国東部(バージニア北部):us-east-1**を選択してください。(※ここで僕は詰まりました。[記事下へジャンプ](#今回の記事の本題に入ります詰みまくった話))

4. 左の欄にEmail Addressesが出て来るので、選択してください。

5. 【Varify a New mail adress】にてを選択して受信可能なメールアドレスを登録してください。

6. ここで【Varify a New mail adress】でもう一つ受信可能なメールアドレスを登録してください。

7. 次に5,6で登録したメールアドレスにAWSからメールが来るので、そのURLにアクセスして、メールアドレスを認証してください。

8. これで完了

### IAMの登録
AmazonSESを使うには、先ほど紹介したアクセスキーIDとシークレットアクセスキーを生成する必要があります。

1. サービスにてIAMページを検索して飛ぶ
2. 左の欄にてユーザーを選択
3. [ユーザーを追加]を選択
4. ユーザ名は好きに入力
5. プログラムによるアクセスにチェックを入れる
6. 下の[次のステップ]を選択
7. 既存のポリシーを直接アタッチを選択
8. SESと検索して、AmazonSESFullAccessを選択
9. あとはスルーしてユーザーの作成してください
10. 作成した時にcsvがダウンロードできるので、ダウンロード
11. アクセスキーIDとシークレットアクセスキーをcsvにて確認
12. これで完了

最後にconfig/settings.pyにてアクセスキーIDとシークレットアクセスキーを入力してください！！

## SESがDjangoで機能するかどうかを確認
確認方法は今回の目標であった『AmazonSESとDjango-SESを用いてsend_mail出来れば目標達成！』であるsend_mailの使用なので、pythonのshellにてインポートして、実行していきます。

```cli:CLI
~/django-ses-sample$ docker-compose run --rm django-ses-sample python3 manage.py shell
>>> from django.core.mail import send_mail
>>> title = '齋藤飛鳥です。'
>>> content = '明日のクリスマス空いてない？'
>>> host_email = 'SESで登録したメールアドレス①'    # 例:asuka@nogi.com
>>> rece_email = ['SESで登録したメールアドレス②']  # 例:['hirochon@bocchi.com']
>>> send_mail(title,content,host_email,rece_email)
```

これでメールが届くはずです(泣)

## 今回の記事の本題に入ります！！！(詰みまくった話)
ついでにという感じで見てやってください。笑

どこで躓いたのかを先に紹介しておきます！

1. **Django3.0で環境を構築したこと**
2. **Regionをアジアパシフィックのムンバイに設定したこと**

### ①Django3.0で環境を構築した件について
正式にリリースされると使いたくなりますよね…笑

ですがDjango3.0にて環境を構築すると、botoかdjango-sesのファイル関係でこんなエラーが出てきます。

```cli:CLI
ImportError: cannot import name 'python_2_unicode_compatible' from 'django.utils.encoding
```

これはどうやらDjango3.0にてPython2の互換性APIを廃止したことによってエラーを吐くようになったみたいです。
[*2 Django公式Documentation](https://docs.djangoproject.com/en/dev/releases/3.0/#removed-private-python-2-compatibility-apis)
[*3 GitHubのissue](https://github.com/treyhunner/django-simple-history/issues/598)

どうやらファイルをいじったら治るみたいなのですが、Dockerコンテナ内(元はPostgreSQLで開発してた)のDBでファイルが見つからず、Django2.2系を使用することによってエラーを吐かなくなりました。

### ②Regionをアジアパシフィックのムンバイに設定した件について
ちらほら目にする『自分の地域と近いリージョンのほうがレスポンス早くなるよ』という情報に体がつい動いてしまいました…

コチラの問題点は色々と文献を探してみたのですが、しっくり来るものはなかったんです。
なので今回は書こうと決断したわけでございます。

ですが恐らく専門家の方たちから指摘が来そうなので先にコチラを書いておきます。

#### settings.pyに設定を書いても無理でした
AWS_SES_REGION_NAMEとAWS_SES_REGION_ENDPOINTを設定することによって「米国東部(バージニア北部)」(us-east-1)以外のリージョン設定が可能なのです。

例えば「米国西部(オレゴン)」(us-west-2)だとAmazon SESでメールアドレスを認証した後に、settings.pyにこのように書くとメールを送ることができます。

```python:settings.py
AWS_ACCESS_KEY_ID = 'AKI***********'       # アクセスキーID
AWS_SECRET_ACCESS_KEY = '**************************'        # シークレットアクセスキー
AWS_SES_REGION_NAME = 'us-west-2'          # 追加した
AWS_SES_REGION_ENDPOINT = 'email.us-west-2.amazonaws.com'   # 追加した
```

ですが！！！**「アジアパシフィック(ムンバイ)」(ap-south-1)だとこのように設定してもメールを送ることができないのです！！**

```python:settings.py
AWS_ACCESS_KEY_ID = 'AKI***********'       # アクセスキーID
AWS_SECRET_ACCESS_KEY = '**************************'        # シークレットアクセスキー
AWS_SES_REGION_NAME = 'ap-south-1'          # 追加した
AWS_SES_REGION_ENDPOINT = 'email.ap-south-1.amazonaws.com'   # 追加した
```

#### じゃあ結局何がだめだったの？？
僕の結論としては、AWSにはリージョンごとに実装されているサービスとされていないサービスが存在いることから、**まだアジアパシフィック(オレゴン)にはそのサービスが実装されていなかった**のではないかと推測しています。

実際オレゴンがSESサービスに追加されたのは最近だそうで、『これからのアップデートで恐らく使えるようになるのではないかな〜』と思っています(/･ω･)/

## さいごに
最後まで読んでいただきありがとうございました。
今回作ったプログラムにallauthパッケージなどを追加していくとしっかりとしたメール機能を実装できるようになるので、是非最速手順を活用していってください。
また間違っている点や感想などでもございましたら、お気軽にコメントください！！

DjangoやAWS,Dockerなどのバックエンドを勉強していたり、機械学習にも少し手を出している姿を発信している僕のTwitterをフォローして頂ければ喜びます！！[@heacet43](https://twitter.com/heacet43)

## 参考文献
*1 Amazon SES における制限(AmazonSES Doccumentation 開発者ガイド)[https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/limits.html]
*2 Django 3.0 release notes (Django documentation) [https://docs.djangoproject.com/en/dev/releases/3.0/#removed-private-python-2-compatibility-apis]
*3 Django3 support·Issue #598·treyhunner/django-simple-history(GitHub) [https://github.com/treyhunner/django-simple-history/issues/598]