【AWS】Amazon EMR ~ EMR内部 から SES で Email を送る ~

■ はじめに

 Amazon EMR から Python / AWS SES により
Email を送ることを考える。

なお、SESについては、以下の関連記事を参照のこと。

Amazon SES ~ Emailサービス ~
https://dk521123.hatenablog.com/entry/2017/04/28/234103

目次

【1】SES で Email を送る方法
 1)AWS CLIコマンド経由でEmail送信する
 2)コード / boto3 API 経由でEmail送信する
【2】注意点
 1)EMRにSES送信する権限を付与する必要がある
 2)EMRで「python xxx.py」は Python2.X系が実行
 3)AWS SES を使うには、boto3 が必要
【3】サンプル
 1)ブートストラップアクション - bootstrap actions 
 2)EMR ステップ - EMR Step

【1】SES で Email を送る方法

以下の2通り。

1)AWS CLIコマンド経由でEmail送信する
2)コード / boto3 API 経由でEmail送信する <<今回はこっちを選択

1)AWS CLIコマンド経由でEmail送信する

簡単なメッセージでいいのであれば、こちらが簡単。

コマンド例

# --from は必須
aws ses send-email --from "from@xxx.cm" --to "to@xxx.cm" --subject "Hello, Title" --html "<p>Hello world</p>"

コマンド仕様

* 詳細は以下の公式サイトを参考。

https://docs.aws.amazon.com/cli/latest/reference/ses/send-email.html

2)コード / boto3 API 経由でEmail送信する

 なお、Pythonコードは、Python3.X系を使うものとする。
(Python2.Xは既にサポート切れだし)

【2】注意点

1)EMRにSES送信する権限を付与する必要がある

『【1】 - 2)コード / boto3 API 経由でEmail送信する』
を採用した場合は、以下も注意

2)EMRで「python xxx.py」は Python2.X系が実行
3)AWS SES を使うには、boto3 が必要

1)EMRにSES送信する権限を付与する必要がある

EMRだけに限ったことではないが、
SES送信権限がないと、以下「エラー内容」が表示され
Email送信できない。

エラー内容

An error occurred (AccessDenied) when calling the SendEmail operation:
User `arn:aws:sts::123456789012:assumed-role/xxxx' is not authorized
 to perform `ses:SendEmail' on resource `arn:aws:ses:eu-west-2:123456789012:identity/from@xxx.com'

IAM role例

       {
            "Sid": "ToSendEmail",
            "Effect": "Allow",
            "Action": [
                "ses:SendEmail",
                "ses:SendRawEmail"
            ],
            "Resource": "*"
        }

参考文献
https://stackoverflow.com/questions/34949316/access-denied-while-sending-email-from-aws-ses-in-lambda-function

2)EMRで「python xxx.py」は Python2.X系が実行

EMR では、現状「python」コマンドは、Python2.X系になっている。
 => Pythonコードが 3.X系であれば、「python3 xxxx.py」にするなどの対応が必要。

3)AWS SES を使うには、boto3 が必要

 AWS SES を使うには、boto3 が必要だが、
現状、デフォルト EMR では、インストールされていない。

 そこで、 pip などでインストールする必要があるのだが
Python3.X系に向ける必要がある。

補足:EMRが外部ネットワークに繋がらない場合

boto3 の wheel ファイルをダウンロードしてきて、
S3に配置する必要がある。

なお、boto3 内で使用されている依存モジュールも含めて、
インストールする必要があるので、こちらも同様の処置が必要。

ここにハマった。
詳細なやり方などの詳細は、以下の関連記事を参照のこと。

https://dk521123.hatenablog.com/entry/2021/07/08/161406

 他にも、S3のホスティングしてpip サーバを立てる的なこと
など色々とあるらしいのでお好みで。。。

【3】サンプル

上記「【1】注意点」を踏まえて以下に分ける。

1)ブートストラップアクション - bootstrap actions 
2)EMR ステップ - EMR Step

1)ブートストラップアクション - bootstrap actions

* セキュリティ上などの制約により、
 インターネットにつながらない環境下では、以下のサイトから
 boto3 の Wheelファイル (今回は「boto3-1.17.107-py2.py3-none-any.whl」)
 をダウンロードしてきて、S3上に置いておく

https://pypi.org/project/boto3/

外部ネットワークに繋がる場合 - install_boto3.sh

#!/bin/bash

sudo pip-3.6 install boto3

外部ネットワークに繋がらない場合

以下の関連記事を参照のこと。

https://dk521123.hatenablog.com/entry/2021/07/10/164833

2)EMR ステップ - EMR Step

run_py_code.sh

#!/bin/bash

# Download python code
s3 cp s3://your-bucket/xxx/send_mail.py ./send_mail.py

# Execute
python3 send_mail.py --mail_from "from-xxxx@gmail.com" --mail_to "to-xxx1@gmail.com,to-xxx2@gmail.com"

send_mail.py

import argparse

import boto3
from botocore.exceptions import ClientError


# If necessary, replace us-west-2 with the AWS Region you're using for Amazon SES.
AWS_REGION = "us-west-2"

# The subject line for the email.
SUBJECT = "Amazon SES Test (SDK for Python)"

# The email body for recipients with non-HTML email clients.
BODY_TEXT = "Hello world"

# The HTML body of the email.
BODY_HTML = """<html>
<body>
  <h1>Hello world</h1>
</body>
</html>
"""

# The character encoding for the email.
CHARSET = "UTF-8"

pritn("Start")

# Create a new SES resource and specify a region.
client = boto3.client('ses', region_name=AWS_REGION)

# Try to send the email.
try:
  parser = argparse.ArgumentParser()
  parser.add_argument("--mail_from")
  parser.add_argument("--mail_to")
  args = parser.parse_args()

  mail_sender = args.mail_from
  mail_recipient_list = args.mail_to.split(',')

  # Provide the contents of the email.
  response = client.send_email(
    Destination={
      'ToAddresses': mail_recipient_list,
    },
    Message={
      'Body': {
        'Html': {
          'Charset': CHARSET,
          'Data': BODY_HTML,
        },
        'Text': {
          'Charset': CHARSET,
          'Data': BODY_TEXT,
        },
      },
      'Subject': {
        'Charset': CHARSET,
        'Data': SUBJECT,
      },
    },
    Source=mail_sender
  )
  print("Email sent! Message ID:"),
  print(response['MessageId'])
except ClientError as ex:
  print(ex.response['Error']['Message'])

pritn("Done")

参考文献

https://aws.amazon.com/jp/premiumsupport/knowledge-center/emr-permanently-install-library/
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/send-using-sdk-python.html

関連記事

Amazon EMR ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2020/02/20/230519
Amazon EMR ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2020/05/27/175610
Amazon SES ~ Emailサービス ~
https://dk521123.hatenablog.com/entry/2017/04/28/234103
Amazon SNS ~ 通知サービス ~
https://dk521123.hatenablog.com/entry/2021/06/03/175213
Python ~ 基本編 / コマンドライン引数 ~
https://dk521123.hatenablog.com/entry/2019/10/11/223651
オフライン環境下で pip install するには
https://dk521123.hatenablog.com/entry/2021/07/10/164833
シェル ~ 引数あれこれ ~
https://dk521123.hatenablog.com/entry/2021/07/11/000421