SNSサブスクリプションのフィルタポリシーで良い知らせだけをメール受信する

Amazon Simple Notification Service (SNS)にサブスクリプションフィルタポリシー(Subscription Filter Policies)を設定し、 プレフィックスマッチング(属性値の前方一致)でフィルタリングしてメール受信する。
2020.03.31

データアナリティクス事業本部、池田です。
「良い知らせと悪い知らせ、どっちから聞きたい?」 って、私の人生で言ってみたいセリフ6位くらいに入っています。
Amazon Simple Notification Service (以下SNS)を使ってメール送信していたのですが、 受信件数が多くなってくると メール件名でフィルタして必要なものだけ受信したいな と思うことがありました。 Slackで受信 していたのでメールクライアントのようなフィルタリングができず、 SNSのトピックを分けるまではしたくないというような状況でした。
そこで、 SNSのサブスクリプションフィルタポリシー を使って、メールの送信時にフィルタをかけることにしました。

イメージ

以下では、「良い知らせ」と「悪い知らせ」(件名)を送信するアプリに対して、 フィルタを設定し、 特定のメールアドレスには「良い知らせ」の方だけをメール送信 させます。 (例えば、運用者は全てのメールを受信する必要があるが、 開発者は一部のメールだけ見ることができれば良いような状況)

(トピックを分けることでもメールの送り分けは可能なので、状況に応じた使い分けは必要かと思います。)

SNSの設定

SNSのトピックとサブスクリプションを作成する必要があります。 今回設定する値は少ないですが、もし困ったら 別の池田ブログ が参考になりそうです。

トピックの作成

SNSトピックを作成します。特に今回の内容に関わる部分は無いので、名前だけ決めて設定はそのままです。

サブスクリプションの設定

トピックのコンソール画面の下の方から、サブスクリプションを設定します。
プロトコルは「E メール」を選択し、エンドポイントには受信したいメールアドレスを入力します。 サブスクリプションフィルターポリシー には以下を設定しました。

{
    "Subject": [{
        "prefix": "良い"
    }]
}

Subject という属性名の値が 良い から始まる(前方一致)場合にメッセージを送信する」 という設定です。 設定方法は こちらのドキュメント をご覧下さい。 (執筆時点では部分一致はできないようです。)
※ここで参照している Subject は実際にメールの件名になる値ではなく、 件名を後述の実装でメッセージ属性に複製して別途格納したものです。

サブスクリプションを作成すると、設定したメールアドレス宛に確認メールが送付され、 リンクをクリックする必要があります。 (業務で使うのであればこの時に、 unsubscribeできないようにしておく のがおすすめです。)

比較用にフィルタポリシー無しのものも作成し、作成したサブスクリプションは↓のような感じです。

テスト

次章でLambdaからメッセージをSNSへ送信しますが、 それが必要が無い場合は、この時点でトピックの画面の「メッセージの発行」からメッセージを発行して確認することもできます。
メッセージ属性に件名と同じ値を設定してあげて下さい。

サンプルメッセージ送信Lambda(Boto3)

AWS Lambda上でBoto3を使用してSNSへメッセージを発行します。 このLambda関数のロールには SNSの発行ポリシー( sns:Publish )が必要 になります。

コードはこんな感じです。(ランタイムのPythonは3.8)

コードの中盤では、「良い」メッセージと「悪い」メッセージをランダムに作成しています。
ポイントは MessageAttributes (メッセージ属性)を設定することです。 Subject (件名)や Message (本文)の値ではフィルタができないので、 件名のSubjectの値を MessageAttributes 内にも格納しておいています。 (Boto3のpublish()については こちら

sns.publish(TopicArn=TOPIC_ARN,
                Subject=subject,
                Message=message,
                MessageAttributes={"Subject": {"DataType": "String",
                                               "StringValue": subject}})

テスト

Lambdaのテスト機能を使用してメッセージを送信してみます。
まずは、フィルタポリシーを設定していない方↓(Gmailで受信)

7通目で良い知らせが来ました。

次に、フィルタポリシーを設定した方↓(Slackのメールで受信)

良い知らせだけ来ました!

おわりに

SQSも含めたもう少し複雑なことをしたい場合は、 こちらのブログ がご参考になるかと思います。

良い知らせだけ聞いて生きていきたいです。