Cloud FunctionsからAmazon SNSを使ってメールを送信する

2022.05.23

データアナリティクス事業本部の鈴木です。

Google Cloud Platform上でイベントが起きた際に、メールを送りたいケースがありました。

このようなときのための構成で、Amazon SESと連携する例は以下の記事で紹介されていますが、私はSESよりAmazon SNSをよく使うので、この記事を参考に、SNSを使った例を試してみました。

構成

以下のような構成としました。

試した構成

Cloud FunctionsでPythonからboto3を使い、Amazon SNSのAPIを呼び出すような作りにしています。Cloud Functionsの起動は、簡単にコンソールのテスト機能で呼び出すことを想定しています。

やってみた

SNSトピックの作成(AWS側)

CloudFormationテンプレートを使って、SNSトピックを作成しました。

AWSTemplateFormatVersion: 2010-09-09
Description: sample sns

Parameters:
  SNSTopicName:
    Description: SNSTopicName for Alarm
    Type: String  
    Default: sample-topic
  NotificationTarget:
    Description: Email for notification
    Type: String

Resources:
  ## SNSトピック
  SnsTopic:
    Type: AWS::SNS::Topic
    Properties: 
      TopicName: !Ref SNSTopicName
      Subscription:
        - Endpoint: !Ref NotificationTarget
          Protocol: email

例えばこのようにスタックを作っておきました。

SNSトピック用のスタックの作成

通知先のメールアドレスの箇所に入力したメールアドレスにサブスクリプションの承諾依頼が届くので、承諾しておきました。

クレデンシャルの準備(AWS側)

AWS SDK for Python を使用して Amazon SNS 経由でメールを送信するため、SNSをキックするためのIAMユーザーを作成し、AWS アクセスキー IDAWS シークレットアクセスキーを用意しました。 以下のように、sns:Publishのみ許可したポリシーを別途作成し、ユーザー作成時にアタッチしておきました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "SNSPublish",
            "Effect": "Allow",
            "Action": "sns:Publish",
            "Resource": "*"
        }
    ]
}

今回はアクセスキーなどを払い出してGoogle Cloud側に渡してしまうので、SNSトピックのARNが分かっている場合は、Resourceで指定して権限を絞っておくとより良いです。

作成したIAMユーザーの認証情報タブなどから、アクセスキーを作成してダウンロードしておきました。アクセスキーの作成方法については以下を参照ください。

関数の作成(Google Cloud側)

Cloud Functionsから通知用の関数を作成します。まず、Cloud Functionsのコンソールに移動し、関数を作成を押しました。

Cloud Functionsの関数作成

次の画面で、構成を入力していきます。基本は以下のように入力しました。トリガーはHTTPを選択して保存しておきました。

構成-基本

Runtime, build, connections and security settingを開くと、ランタイム環境変数を入力する箇所があるので、以下のように記入しました。特に赤字の箇所は、AWS側で作成したリソースに合わせて入力しました。

ランタイム環境変数

コードの画面では、実行するプログラムの設定を行いました。今回は以下のように入力しました。

コード入力例

まず設定は以下としました。

  • ランタイム: Python 3.9
  • エントリーポイント: send_email

またコードは以下のものを入力しました。

main.py

import os

import boto3


def send_email(request):
    # 引数取得
    request_json = request.get_json()
    subject = request_json['subject']   # メールタイトル
    message = request_json['message']   # メール本文

    # 環境変数取得
    AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
    AWS_SECRET_ACCESS_KEY_ID = os.getenv('AWS_SECRET_ACCESS_KEY_ID')
    TOPIC_ARN = os.getenv('TOPIC_ARN')

    # SNSクライアント
    client = boto3.client(
        'sns',
        aws_access_key_id=AWS_ACCESS_KEY_ID,              # アクセスキー
        aws_secret_access_key=AWS_SECRET_ACCESS_KEY_ID,   # シークレットキー
        region_name='ap-northeast-1'
    )

    # メールの内容作成
    sns_request = {
        'TopicArn': TOPIC_ARN,
        'Message': message,
        'Subject': subject
    }

    # メール送信
    response = client.publish(**sns_request)

    print(response)
    return "OK"

アクセスキーなどのクレデンシャル情報は、環境変数から渡すこととしました。

boto3のインストールは、requirements.txtに記載することでできました。以下のように記載しました。

requirements.txtの記載

requirements.txt

boto3>=1.17.100

入力後は、問題なかったので、左下のデプロイボタンを押してデプロイしました。

デプロイボタン

しばらくして、関数が作成されたことを確認できました。

関数の作成完了

テストメールの送信

関数が作成されたので、早速SNSとの疎通を確認しました。関数の名前をクリックして、テスト中タブを押しました。

テスト中タブ

するとトリガーとなるイベントを入力できるので、以下のように入力してテストを実行しました。

トリガーとなるイベントを入力してテストを実行する

{
    "subject" : "テストメール",
    "message" : "Cloud Functions からSNS経由のメールです。"
}

SNSトピックで設定したメールアドレスで届いたメールを確認すると、確かにメールが受信できました。

届いたメール

最後に

今回はCloud FunctionsからAmazon SNSを使ってメールを送る方法をご紹介しました。参考になりましたら幸いです。