フラミナル

考え方や調べたことを書き殴ります。IT技術系記事多め

Amazon SES APIをPythonで使ってみる

f:id:lirlia:20170708122335p:plain

AWS Lambdaからメールを送りたい

Twitterの検索結果をコネコネして毎日自分にメールを飛ばしたいなあと思い立ちました。

そんなちょっとした思い付きに使えるのがAWS Lambda。(Lambdaの説明は省きます)

今回はLambdaの結果を自分にメールでを送りたいので、Amazonで提供されているAmazon SESについて調べてみます。

最終的には、python+lambda+SESでコードを書いていきます。

Amazon SES SMTP とは

基本は公式サイト に書かれていることが全てです。

Amazon SES は、ユーザー自身の E メールアドレスとドメインを使用して E メールを送受信するための、簡単で費用効率の高い方法を提供する E メールプラットフォームです。

うん、メールを送る仕組みですね。SMTPサーバーという理解です。

バウンスされた E メール、苦情が生成された E メール、受取人のメールサーバーに正常に配信された E メールに関する通知を受け取るように、Amazon Simple Notification Service(Amazon SNS)をセットアップします。Amazon SES を使用して E メールを受信するときに、E メールのコンテンツを Amazon SNS トピックに公開することができます。

Amazonの別サービスのSNSへの通知もできるようですね。

Amazon SES を介して E メールを送信する

参照:Amazon SES を介して E メールを送信する - Amazon Simple Email Service

SESを使ってEメールを送信する方法は3種類あります。

  • Amazon SES コンソール
  • SMTP インターフェイス
  • Amazon SES API

Amazon SES コンソール

Webブラウザ上でボタンをぽちぽちして送信するやつです。

SMTP インターフェイス

メールソフトなどでSTMPの設定をする方法と、プログラミング言語のSMTP関数でSESのSMTPを設定する方法の2つがあります。

大体のケースでは自分で作ったアプリケーションからメールを送りたいと思いますので、後者がよく使われそうですね。

Amazon SES API

  • Amazon SES APIをHTTPS経由で呼ぶ
  • AWS SDK
  • AWS Cmdline
  • AWS Tools for Windows PowerShell など

を使ってメール送信処理を行います。

SMTPサーバーのアドレスやポート番号を指定すればいいだけのSMTPインターフェースの方が使い勝手が良さそうですが、SES APIではより細かい制御ができるところにメリットがあります。

AWS SDK は、Amazon SES API の低レベル機能を、詳細を自動的に処理する高レベルのデータ型および関数の呼び出しでラップします。AWS SDK は Amazon SES のオペレーションだけでなく、基本的な AWS 機能(リクエスト認証、リクエスト再試行、エラー処理など)も提供します。

今回はAWS SDKを使ってみようと思います。

メール送信をする前の準備

こちらのサイトに従って準備を進めます。

Amazon SES クイック スタート - Amazon Simple Email Service

ステップ 1: AWS にサインアップ

アカウントがある前提なのでサインアップは飛ばします。

ステップ 2: E メールアドレスの確認

Amazon SES では、E メールアドレスまたはドメインを検証して、それを所有していることを確認し、他のユーザーに使用されないようにする必要があります。このセクションでは、個々の E メールアドレスの検証について説明します。

こちらの手順に沿ってメールを検証すると、検証したメールアドレスにAmazonからメールが送られてきますので承認しましょう。

Amazon SES での E メールアドレスの検証 - Amazon Simple Email Service

ステップ 3: 最初の E メールの送信

メールを送ります。

地味にNavigationペインとかIdentity Managementというところが見つからなかったのですが、ようするに左側の[Email Addresses]をクリックすれば良いです。(探索力不足)

Amazon SES コンソールを使用して E メールを送信する - Amazon Simple Email Service

ステップ 4: バウンスや苦情の処理方法の検討

メールを送った時、アドレスが間違っていたり経路がおかしかったりと言う理由で「MAILER-DAEMON」というメールが帰ってきた経験はないでしょうか? 相手に届かなかったよ連絡のことをバウンスといいます。

自分自身にメールを送る予定なので今回は気にしませんのでカットです。

サイトはこちら:バウンスと苦情の処理 - Amazon Simple Email Service

説明でもバウンスが高いとアカウントがシャットダウンされる事もあるようなので、気をつけましょう。

バウンス率や苦情率が高くなると、アカウントがシャットダウンされる事態を招きかねません。したがって、バウンスや苦情が発生している受取人のアドレスを受取人リストから削除するためのプロセスを備える必要があります。

ステップ 5: Amazon SES サンドボックスの外への移動

未確認の E メールアドレスに E メールを送信する、1 日あたりに送信できる E メールの数を増やす、高速で E メールを送信するためには、アカウントをサンドボックスの外に移動する必要があります。このプロセスでは、サポートセンターで SES Sending Limits Increase ケースを開く必要があります。

1日1通程度想定なので不要ですね。

なんでサンドボックスの中から初期はメールを送ってるんだ? と思ったらセキュリティ対策のようです。

お客様を詐欺行為や不正行為から保護し、ISP およびメールの受信者に対する信頼性を確立できるようにするため、新しいユーザーには無制限の Amazon SES の使用をすぐに許可していません。新しいユーザーは、最初に Amazon SES のサンドボックスに配置されます。サンドボックスでは、すべての Amazon SES E メール送信方法と機能へフルアクセスができるので、サービスのテストおよび評価ができます。 Amazon SES サンドボックスの外への移動 - Amazon Simple Email Service

SES APIを実際につかってみる(by Python)

Amazon SES API を使用して E メールを送信する - Amazon Simple Email Service

  • raw クエリのリクエストとレスポンスを作成する - API を直接呼び出すため、これは最も高度な方法です。クエリのリクエストとレスポンスを作成する方法については、「Amazon SESクエリ API」を参照してください。
  • AWS SDK を使用する - AWS SDK は、Amazon SES API の低レベル機能を、詳細を自動的に処理する高レベルのデータ型と関数呼び出しでラップします。また、リクエスト認証、リクエストの再実行、エラー処理などの(Amazon SES API には含まれていない)基本的な機能が用意されています。
  • コマンドラインインターフェイスを使用する - AWS Command Line Interface は、Amazon SES 用のコマンドラインツールです。さらに、PowerShell 環境でのスクリプト作成用に AWS Tools for Windows PowerShell も用意しています。

いろいろとやり方があるようですが、最終ゴールはHTMLメールを自分のメアドに送信する事を目標としますのでそんなに難しい事は必要ありません。AWS SDK for Pythonを使ってPythonでコードを書いていきます。

なおAmazon SES APIでは2種類の方法でメールを送信できるそうです。

  • フォーマット済み - Amazon SES は、正しくフォーマットされた E メールメッセージを構成して送信します。ユーザーは、送信元と宛先のアドレス、件名、メッセージ本文を入力するだけです。その他はすべて Amazon SES が処理します。詳細については、「Amazon SES API を使用してフォーマット済み E メールを送信する」を参照してください。
  • raw - E メールメッセージを手動で構成して送信します。自分で E メールヘッダーおよび MIME の種類を指定します。E メールのフォーマット作業を自分で行った経験があれば、raw インターフェースにより、メッセージの構成をより詳細に制御できます。詳細については、「Amazon SES API を使用して raw Eメールを送信する」を参照してください。

簡単にやりたいのでフォーマット済みですもちろん。 Amazon SES API を使用してフォーマット済み E メールを送信する - Amazon Simple Email Service

Amazon SES API を使用してフォーマット済み E メールを送信する

Amazon SES API は、フォーマット済み E メールを構成して送信できるようにする SendEmail アクションを提供します。SendEmail には、送信元アドレス、宛先アドレス、メッセージの件名、メッセージの本文(テキストか HTML、またはその両方)が必要です。SendEmail の詳細については、「Amazon Simple Email Service」を参照してください。

注記 E メールアドレスは、7 ビット ASCII 文字列になっている必要があります。送信先または送信元の E メールアドレス内で、ドメインの部分に unicode 文字が含まれる場合は、Punycode を使用してドメインをエンコードする必要があります。詳細については、「RFC 3492」を参照してください。

ふみふむ。なるほど。

AWS SDK for Python を探す

Botoと呼ばれるAWS用のSDKがPython向けに提供されています

Boto is the Amazon Web Services (AWS) SDK for Python, which allows Python developers to write software that makes use of Amazon services like S3 and EC2. Boto provides an easy to use, object-oriented API as well as low-level direct service access.

send_email に関する使い方はこちら→Boto SES — Boto 3 Docs 1.4.4 documentation

今回使うSendEmailAPIはこちら

AWSの準備

asw configure

なおaws configureによってAWSの認証情報を先に登録しておいてください。

ちなみにSESは2017.7現在日本のリージョンでは使えませんので、普段日本のを登録されている方は変更しておきましょう。

IAMへのSES許可登録

使用するアカウントのIAMにSESを利用する権限を与えておきます。与えないとこんなエラーがでますよ。

botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the SendEmail operation: User `arn:aws:iam::xxxxxxx:user/xxxxxxx' is not authorized to perform `ses:SendEmail' on resource `arn:aws:ses:us-east-1:xxxx:identity/xxxx@gmail.com'

IAMからAmazonSESFullAccessを対象アカウントに許可しておきましょう。

コードを書く

GitHubにサンプルコードを置いておきました。 lirlia/boto3-sendemail-sample: This repository is a sample of boto3 sendemal

import boto3

def send_mail(fr, to, title, body):
    '''
    fr : from address
    to : dest address
    title : title
    body : content
    '''

    client = boto3.client('ses')

    #
    # API reference
    # https://boto3.readthedocs.io/en/latest/reference/services/ses.html#SES.Client.send_email
    #
    response = client.send_email(
        Source=fr,
        Destination={'ToAddresses': [to]},
        Message={
            'Subject': {
                'Data': title
            },
            'Body': {
                'Html': {
                    'Data': body
                }
            }
        }
    )
def main():
    fr = 'from address'
    to = 'dest address'
    title = "title"
    body = "<html><body><p>content</p></body></html>"
    send_mail(fr, to, title, body)

if __name__ == '__main__':
    main()

これで無事メールが送信できましたね!

次回はこいつをLamdaにのせていきたいと思います。