EC2にデプロイしたDjangoからAWS SESを使う

# はじめに
EC2からメールを送信する方法はいくつかあります。
自分用メモとして、その中でも一番メジャーであろうSESを使ったメール送信について残しておきます。
# ドメインの取得
メールを送信するためにはドメインが必要となります。（~@mail.comの部分ですね）
こちらは以下のサイト参照で取得しておきましょう。
### Route53から直接購入する場合
「ドメインのRoute 53への登録」までですね。
https://dev.classmethod.jp/articles/relaxing-send-limit-and-removing-sandbox-restriction-in-ses/

### 他のサービスを使う
ドメインはRoute53で買わずとも、他のドメイン登録サービスを使うこともできます。
有名なのはお名前.comですね。
先にドメインを取得しておいて、お名前.comの設定ページのネームサーバー欄にRoute53のNSレコードを貼り付けたら完了です。
お名前.comで取得するとキャンペーンとかで安くなる事が多いのでおすすめです。

こちらもDevelopersIOさんのサイトを貼っておきますね。
https://dev.classmethod.jp/articles/route53-domain-onamae/

# Django側
### django-sesのインストール
ドメインの取得ができたら次はDjango側での作業です。
DjangoではDjango-sesをインストールすることで簡単にDjangoからSESを操作する事ができます。
~~~
pip install django-ses
~~~
django-sesではbotoというpythonライブラリとAWSサービスをつなぐものを必要としますので、こちらもインストールが必要です。
~~~
pip install boto3
~~~
これにより、Djangoの標準からSESを使う事ができるようになりました。
### setting.pyの修正
setting.pyを開いて以下のように修正しましょう。
なお、...は省略の意味です。
~~~python
INSTALLED_APPS = [
    ...
    'django_ses' #追加する

]
...
AWS_SES_REGION_NAME="ap-northeast-1" #追加する
AWS_SES_REGION_ENDPOINT="email.ap-northeast-1.amazonaws.com" #追加する
EMAIL_BACKEND="django_ses.SESBackend" #追加する
DEFAULT_FROM_EMAIL = "no-reply@mail.com" #追加する、@の後ろは取得したドメイン
~~~
各項目について簡単にメモしておきます。
とは言っても名前でなんとなくわかりますけどね。

**AWS_SES_REGION_NAME**
SESを動かしているリージョンを選択します。東京リージョンなら例の通りです。

**AWS_SES_REGION_ENDPOINT**
SESのエンドポイントです。Djangoはここにアクセスします。
似たようなものにSMTP endpointがあります。こちらではないのでご注意ください。

自分の認識だと、AWSサービスとしてではなくシンプルにSMTPサーバーとしてSESを使いたいときに使うものだと思ってます。

**EMAIL_BACKEND**
その名の通り、Django内でEmailサービスの根幹となるアプリケーションを選択します。
デフォルトでは以下の様になっていると思います。
~~~python
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
~~~
これはSMTPサーバーを指定してDjangoからメールを送るときのデフォルトのバックエンドです。
setting.py内でSMTPサーバーの設定をすれば、このデフォルトのバックエンドでメール送信をする事ができますが、今回はdjango-sesのバックエンドを指定しておきましょう。

**DEFAULT_FROM_EMAIL**
メールの送信元を設定します。
これを設定しないとデフォルトでwebmaster@localhostが送信元に設定されてしまいます。
SESにlocalhostのドメインはないのでエラーが出ます。

Django側の設定は以上で終了です。
# EC2側
続きましてEC2側の設定です。
Djangoが動いているEC2とSES間の認証にはIAMロールを使用します。

先程のsetting.py内に
~~~python
AWS_ACCESS_KEY_ID = "***********************"

AWS_SECRET_ACCESS_KEY = "***********************"
~~~
のようにIAMユーザーのアクセスキーとシークレットアクセスキーを入力することでも認証することは可能です。
ただ、環境変数ならまだしもアクセスキーをプログラム中に書くのはまずいのでIAMロールを使用します。

### ポリシーを作成する
IAMのコンソール画面からポリシーをクリックして、ポリシーを作成をクリックしましょう。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1049804/2a0da0df-bd4f-cf2d-5f3a-4e6f76f6a45b.png" width="70%">

### ポリシーを入力
ビジュアルエディタから入力しても良いですが、とくにこだわりがなければJSONでこの3つを書いておけばいいかと思います。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1049804/eeaf7894-4daa-6b41-7422-120b5733ee1a.png" width="70%">
↓コピー用
~~~JSON
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "SESSendMail",
            "Effect": "Allow",
            "Action": [
                "ses:SendEmail",
                "ses:SendRawEmail",
                "ses:GetSendQuota"
            ],
            "Resource": "*"
        }
    ]
}
~~~

GetSendQuotaですが、SESには送信できる上限値があって、GetSendQuotaで知ることができるみたいです。
そのためロールにこれがないとエラーとなります。
https://docs.aws.amazon.com/ja_jp/ses/latest/dg/manage-sending-quotas-monitor.html

あとは画面にしたがって進んでいきましょう。
途中で名前を設定する画面がありますが、この名前はあとで使うので覚えておきましょう。

![スクリーンショット 2022-04-29 0.10.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1049804/1bfea574-f932-68cd-cd1c-0ded4645698a.png)

これでポリシーは完成しました。
### ポリシーをアタッチしてIAMロールを作成
次にいま作成したポリシーをIAMロールを作成してアタッチします。
ロールをクリックしましょう・
![スクリーンショット 2022-04-15 23.44.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1049804/24ac1649-8cb7-bd42-67c4-2a8bdb939d07.png)

### ロールを作成をクリック
![スクリーンショット 2022-04-15 23.44.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1049804/3fed0c63-1928-4efe-120d-faf8fe443e28.png)

### エンティティ選択
今回はAWSサービスにIAMロールをつけるので、AWSサービスを選びます。
ユースケースはEC2を選んで次へいきましょう。
![スクリーンショット 2022-04-15 23.44.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1049804/d9a512c6-c775-03c8-b16f-d99de812e139.png)

### アタッチするポリシーを選択
続いて作成中のロールにアタッチするポリシーを選択します。
ここには自分が作ったポリシーだけでなく、AWS側で最初から用意されているポリシーも表示されています。
先ほどポリシー作成時につけた名前「SES_SendMail」で検索しましょう。

見つかったらチェックを入れて次へ進んでください。
![スクリーンショット 2022-04-29 0.16.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1049804/2b92673c-47f4-7474-b0e5-f0898f96f757.png)

### 名前を入力して作成完了
最後にこのロールの名前を入力して作成ボタンを押しておきましょう。

お疲れ様でした！これでロールの作成まで完成しました。
![スクリーンショット 2022-04-29 0.16.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1049804/77c894a2-e13f-59db-17f9-c14c5eec025c.png)

## EC2にアタッチ
ここまでくればあともう少しです！

### IAMロールを変更をクリック
![スクリーンショット 2022-04-29 0.24.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1049804/d09194af-68de-d2f3-ee07-420b05898cb0.png)

### ロールを選択して保存
ここで先程作成したロールを選択してください。
もし、さきほどロールを作成する先にエンティティでEC2を選んでないとここに表示されないので注意しましよう。
![スクリーンショット 2022-04-29 0.24.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1049804/bbe0785d-5128-8670-1f71-dc4bc7e8c4b0.png)


# Django側の設定
こんな関数を作っておいて、呼び出してやればメールを送る事ができます。
~~~python
from django.core.mail import EmailMultiAlternatives

def send_email(subject,text_content,html_content,from_email,to_emails):
    msg = EmailMultiAlternatives(subject, text_content, from_email, [to_emails])
    msg.attach_alternative(html_content, "text/html")
    msg.send()
~~~
https://docs.djangoproject.com/ja/4.0/topics/email/
詳しくは、Djangoの公式ドキュメントに書いてありますが簡単に説明しますと、
subject:メールタイトル
text_content:プレーンテキストのメール本文（受信者がHTMLメールに対応してない場合に表示する用）
html_content:HTMLで書かれたメール本文
from_email:送信元
to_emails:送信先(リストで指定できます。)

ちなみに試してはいませんが、HTMLメールを送る必要がない場合はこれだけでも送れるみたいです。
~~~python
from django.core.mail import send_mail

send_mail(
    'Subject here',
    'Here is the message.',
    'from@example.com',
    ['to@example.com'],
    fail_silently=False,
)
~~~


# まとめ
いかがでしょうか。
AWSではEC2にメールサーバーを建てなくても、マネージドサービスで簡単にメールを送信することができます。
しかも、今回のようにEC2にホストされているアプリケーションからSESを使ってメール送信した場合には、62,000通/月まで無期限無料枠があるので個人開発だとほぼ無料枠に収まるのではないでしょうか。