【AWS】Amazon SES+Lambdaで各種メールサービスの通知をDiscordへ転送する

AWS

今回はAWSに関する記事です。
掲題にある各種メールサービスの通知をDiscordへ
転送する方法を解説していきます

  • 本記事のターゲット
  • 構成図
  • 本構成の事前確認事項/注意事項
  • Discordの設定
  • Lambdaの設定
  • S3の設定
  • Route53の設定
  • AmazonSESの設定
  • メールクライアントの転送設定
  • 最後に
  1. 【AWS】Amazon SES+Lambdaで各種メールサービスの通知をDiscordへ転送する
    1. 本記事のターゲット
    2. 構成図
    3. 本構成の事前確認事項/注意事項
    4. Discordの設定
      1. (1)通知用のサーバー作成
      2. (2)どういうサーバーなのか質問される
      3. (3)サーバー名を入力して新規作成
      4. (4)テキストチャンネルを通知用にひとつ作成
      5. (5)チャンネル作成時の設定
      6. (6)メンバーまたはロールの追加
      7. (7)Webhook URLの作成
      8. (8)ウェブフックを作成
      9. (9)Webhook URLを取得
      10. (10)おまけ:アイコンとWebhookの通知名を設定
    5. Lambdaの設定
      1. IAMロールの作成
        1. (1)ロールを作成
        2. (2)信頼されたエンティティを選択
        3. (3)許可を追加
        4. (4)名前、確認、および作成
        5. (5)作成確認
      2. Lambda関数の作成
        1. (1)Event Functionsの作成
        2. (2)イベント関数の作成
        3. (3)作成成功後の画面
        4. (4)コードの記述
        5. (5)一般設定の編集押下
        6. (6)タイムアウト秒数の設定
        7. (7)環境設定の編集押下
        8. (8)環境変数の設定
    6. S3の設定
        1. (1)S3バケットを作成する画面
        2. (2)バケットを作成
        3. (3)ライフサイクルルールを作成する
        4. (4)ライフサイクルルールの設定
        5. (5)ライフサイクルルール設定
        6. (6)SESからのアクセス許可
        7. (7)バケットポリシーの編集
    7. Route53の設定
    8. AmazonSESの設定
      1. ID作成
        1. (1)IDの一覧画面
        2. (2)IDの作成
        3. (3)ID作成完了確認
        4. (4)Route53のホストゾーン確認
        5. (5)MXレコードを作成
        6. (6)MXレコードの作成確認
      2. Eメール受信設定
        1. (7)ルールセットの作成
        2. (8)ルールセットの有効化
        3. (9)ルールの作成
        4. (10)ルール設定の定義
        5. (11)受信者の条件の追加
        6. (12)アクションの追加
        7. (13)レビュー
        8. (14)Lambdaへのアクセス許可追加
        9. (15)ルールの作成確認
    9. メールクライアントの転送設定
      1. Gmailによる動作確認
      2. (補足)Gmailのフィルタ動作について
    10. 最後に

【AWS】Amazon SES+Lambdaで各種メールサービスの通知をDiscordへ転送する

本記事のターゲット

Outlookなどに代表される各種メールサービスは、
自前でメールの仕分け機能を備えていることが多いです。

受信トレイ へ格納された新着メールを、送信元や件名に応じて、
フォルダに振り分ける機能。
自分に関係ある、もしくは気をつけなければいけないメールを
固定の場所へ配置することで、対処の優先度が高い連絡を見落とさないようにする。

上記を利用している人は多いと思います。

メールソフトを起動することが始業時の日課になっている方も多いと思いますので
業務だとコレで問題ないのですが、

プライベート用のメールソフトは毎日確認しない場合が多く
なおかつ連絡用のメールアドレスは複数所持しており、
数日経過してから連絡があったことに気づく

という状況になっている方も多いと考えます。(筆者もこのパターン)

そこで本記事では、通知に気づきやすいDiscordへメール受信を知らせることにより
いろいろなメールサービスへ届く「重要な連絡」や「見落としたくないメッセージのみ」を
より早く気づける仕組みを構築していきます。

本記事は、以下のような方を対象としています。

  • 複数のメールアドレスを所持しており、メールの確認が煩雑になっている方
  • 普段あまり確認しないメールアドレスに、重要な連絡が届くことがある方
  • すべての新着メールではなく、特定の送信元や件名に該当するメールだけを通知したい方
  • Discordを日常的に利用しており、通知先を一本化したい方
  • AWSを利用して、メール通知の仕組みを構築してみたい方

なお、本記事では既存のメールサービスが持つ振り分け/転送機能を活用するため、
メールサービスそのものをAWSへ移行する必要はありません。

構成図

今回は以下のようなAWSの構成を作成します。(設定する連携サービスも記述)

補足事項:
本記事ではDiscordを利用しますが、Lambdaの通知処理を変更することで
Slackなどへの連携も可能です

本構成の事前確認事項/注意事項

本構成を利用するにあたり、以下の事項を事前に確認してください。

  • メールの自動転送環境:通知対象のメールをAmazon SES宛てに自動転送できる環境が必要です。
  • AWS環境:Amazon SES、AWS Lambda、Amazon Route 53を利用できるAWSアカウントが必要です。
  • ドメイン:Amazon SESでメールを受信するための独自ドメイン、または利用可能なサブドメインが必要です。
  • Discord環境:通知先となるDiscordサーバーと、Webhookを設定できる権限が必要です。
  • 通知の受信方法:本記事ではDiscordのスマートフォンアプリで通知を確認する想定ですが、PCアプリでも利用できます。

なお、AWSの各サービスには利用料金が発生する場合があります。

本記事では、特に指定がなければすべてap-northeast-1(東京リージョン)
で構築するものとします。
またIAMやRoute53はグローバルで固定されており、リージョンを選択できません。
※悩まず手順通りに設定してください

Discordの設定

Discordアカウントの作成とログインは完了しているものとします
また、PCのデスクトップアプリ版を利用して解説します

(1)通知用のサーバー作成

左ペインのサーバーを作成するボタンを押下すると、中央にポップアップが出現します。
とりあえず「オリジナルの作成」をクリック。
※サンプルが切り抜きだらけになっているあたりご容赦ください。。。

(2)どういうサーバーなのか質問される

あまり気にせずイチバン上のを選択しておきましょう。
スキップしてもいいみたいです。

(3)サーバー名を入力して新規作成

「検証用サーバー」とします。
※あとで変更できるので、適当な名前で問題なし

(4)テキストチャンネルを通知用にひとつ作成

テキストチャンネル横の + をクリックします。
一般はメンバー招待したときの初期スポーン地点だったりするので一応分割しておきます。
※メンバー招待したときの初期スポーン地点は後で変更可能

(5)チャンネル作成時の設定

テキスト、チャンネル名「通知」、プライベートチャンネルをONにして作成します。
※チャンネル名は後で変更可能

(6)メンバーまたはロールの追加

今設定する必要ないので、スキップします。

(7)Webhook URLの作成

まずは「チャンネルの編集」を押下します(チャンネル右の歯車)マークです

(8)ウェブフックを作成

連携サービス→ウェブフックを作成 を押下します。

(9)Webhook URLを取得

「ウェブフックURLをコピー」を押下すると、クリップボードにコピーされるので
メモ帳などに貼り付けて内容確認します。

以下のようなURLが取得できるので控えておきます。(Lambda作成時に利用する)
※筆者のWebhookは公開できないので途中で切ってますが、実際にはもっと長いです。
 合計120文字ぐらいあります。

(10)おまけ:アイコンとWebhookの通知名を設定

キャラ設定的な、システム通知の名前と画像を編集できます。
※特に設定しなくてもいいです。デフォルトだと味気ないと感じるなら設定してみてください

Lambdaの設定

IAMロールの作成

Lambdaへ付与するIAMロールを作成します。

この程度のロールならLambda作成時の自動生成に頼ってもいいのですが
「ランダムな名前をつけられて管理できなくなるのが嫌」なので
毎回命名しています。※名前は後で変更できません

  • ロール名:Lambda-to-Discord
  • ユースケース:Lambda
  • 許可ポリシー:AWSLambdaBasicExecutionRole
(1)ロールを作成
(2)信頼されたエンティティを選択
(3)許可を追加
(4)名前、確認、および作成
(5)作成確認

Lambda関数の作成

以下の設定値でLambda関数を作成していきます。

  • 関数名:Lambda-to-Discord
  • ランタイム:Python 3.14 (現時点の最新版を選択)
  • カスタム実行ロール:Lambda-to-Discord
(1)Event Functionsの作成
(2)イベント関数の作成
(3)作成成功後の画面

いつの間にか表示されるようになってますが今回は利用する必要ありません。
✕閉じで問題なし。

(4)コードの記述

以下のコードを貼り付けます⇩

import json
import os
import urllib.request

WEBHOOK = os.environ["DISCORD_WEBHOOK_URL"]


def post_discord(content: str) -> int:
    payload = {"content": content}
    data = json.dumps(payload).encode("utf-8")

    req = urllib.request.Request(
        WEBHOOK,
        data=data,
        headers={
            "Content-Type": "application/json",
            "User-Agent": "aws-lambda/discord-webhook",
        },
        method="POST",
    )

    with urllib.request.urlopen(req, timeout=5) as resp:
        return resp.status


def lambda_handler(event, context):
    rec = event["Records"][0]

    # SESから受信したメール情報を取得
    mail = rec["ses"]["mail"]
    headers = mail.get("commonHeaders", {})

    subject = headers.get("subject", "(no subject)")
    sender = headers.get("from", ["(unknown)"])
    recipients = mail.get("destination", [])

    # Discordへ送信するメッセージを作成
    content = (
        f"📩 **メール通知**\n"
        f"- **件名**: {subject}\n"
        f"- **送信元**: {', '.join(sender)}\n"
        f"- **宛先**: {', '.join(recipients)}"
    )

    # Discordの文字数制限対策
    content = content[:1900]

    status = post_discord(content)
    print(f"discord_status={status}")

    return {"ok": True, "status": status}

[コードタブ]→[lambda_function.py(上記を貼付け)]→[Deploy 押下]

※コードは長くなりがちですが、ちゃんと貼り付けできていれば見切れていても問題なし。

(5)一般設定の編集押下

お作法的に、タイムアウト秒数を引き伸ばします。
※デフォルトの3秒は短すぎ、これが原因で処理失敗することが多々あります。

(6)タイムアウト秒数の設定

雑に3分まで引き伸ばします。

(7)環境設定の編集押下

コードに記述されている変数を定義します。
コードにはWebhook URLなどが直接記入されていません。
代わりに、Lambda機能の環境変数へ、該当のパラメータを設定します。

(8)環境変数の設定

ここで、最初に作成したウェブフックURLを埋め込みます。

  • キー:DISCORD_WEBHOOK_URL
  • 値:(先ほど取得した、DiscordのWebhook URL)

S3の設定

転送したEmailの原本を一時保管するためにS3を配置します。

S3のバケット名は長らく、全世界で一意でなければなりませんでした。
最近は「アカウントのリージョナル名前空間」を選択すると、
以下のように自動的に一意のバケット名に変換されます。

[バケット名]+[-AWSアカウントID]

手順的には毎回同じネーミングで提供できるようになりました。
※AWSはテックブロガーに優しくなりました。

(1)S3バケットを作成する画面
(2)バケットを作成

以下を指定してバケットを作成します。
※これ以外はデフォルト値で問題なし

  • バケット名前空間:アカウントのリージョナル名前空間
  • バケット名の接頭句:ses-reception-email

入力したらスクロールし、右下にある[バケットを作成]を押下します。

(3)ライフサイクルルールを作成する

メールの原本は一時保管のため、自動削除するルールを設定します。

(4)ライフサイクルルールの設定

以下を指定してルールを作成します。
既存のS3に対して本設定を行わず、本記事手順専用のS3バケットに対してのみ設定してください。
※S3上のすべてのオブジェクトが日数で削除されてしまいます

  • ライフサイクルルール名:ses-reception-email
  • ルールスコープを選択:バケット内のオブジェクト全てに適用
  • ライフサイクルルールのアクション:オブジェクトの現行バージョンを有効期限切れにする
  • オブジェクト作成後の日数:3
(5)ライフサイクルルール設定
(6)SESからのアクセス許可

作成時点の状態ではSESからS3へアクセスすることができませんので、
ポリシーを設定します。

(7)バケットポリシーの編集

以下のコードを貼り付けします。

このままでは動きませんので、AWS画面右上からアカウントIDを取得し
【あなたのAWSアカウントID】部分を置き換えて使用してください。


{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowSESPuts",
      "Effect": "Allow",
      "Principal": {
        "Service": "ses.amazonaws.com"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::ses-reception-email-【あなたのAWSアカウントID】-ap-northeast-1-an/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceAccount": "【あなたのAWSアカウントID】"
        }
      }
    }
  ]
}

(筆者のAWSアカウントは伏せてます)以下のように記述します。

Route53の設定

筆者の環境では、既存ドメインからサブドメインを権限委譲して利用しています。
既に独自ドメインを所有している場合は新たにドメインを取得せず、
サブドメインを利用して構築することも可能です。

今回はRoute 53を使用したサブドメインの権限委譲手順を簡単に紹介します。

  1. 委譲元のドメイン名を確認(例:blog.addache.jp)
  2. 構築中のAWSアカウントでパブリックホストゾーンを作成(例:mail.blog.addache.jp)
  3. 作成したホストゾーンに自動生成されたNSレコードの値(ネームサーバー)を取得
  4. サブドメイン権限委譲元のドメインのホストゾーンを開く(例:blog.addache.jp)
  5. NSレコードを作成(例:mail.blog.addache.jp)し、取得したネームサーバーを登録する

ドメインの管理環境によって設定方法は異なります。
既にSESで利用するドメインのDNSレコードを管理できる場合は、サブドメインの権限委譲は必須ではありません。

以下は検証用に作成したパブリックホストゾーン例です。
このホストゾーンは、後続のSES設定時に利用します。

※上記サブドメイン権限委譲手順も実施しています

  • ドメイン名:mail.blog.addache.jp

AmazonSESの設定

ID作成

(1)IDの一覧画面

SESの初期画面から左ペインを開いて、IDの作成まで進めます。

(2)IDの作成

以下のように設定します。

  • ドメイン名:mail.blog.addache.jp
  • IDタイプ:Easy DKIM
  • DKIM署名キーの長さ:RSA_2048_BIT
(3)ID作成完了確認

作成後画面をリロードして、以下のIDステータスへ変わることを確認します。

(4)Route53のホストゾーン確認

先程作成したホストゾーンの画面を開き、
以下のようにCNAMEが自動生成されていることを確認します。
さらに「レコードを作成」をクリック。

(5)MXレコードを作成

以下のようにレコードを作成します

  • レコード名:(何も記入しない)
  • レコードタイプ:MX
  • 値:10 inbound-smtp.ap-northeast-1.amazonaws.com
(6)MXレコードの作成確認

以下のようにMXレコードと自動生成されたCNAMEレコードが表示されていれば完了です。

Eメール受信設定

(7)ルールセットの作成

SESに戻り、Eメール受信設定を進めます。
※送信設定は今回行いません

Lambdaと同じ名前でルールを作成します。

  • ルールセット名:Lambda-to-Discord
(8)ルールセットの有効化

初期状態だと無効になっているので、右上のボタンを押下し忘れず有効化します。

ポップアップが出てきますがそのまま「有効として設定」を押下すれば問題なし。

(9)ルールの作成

ルールセットの作成が完了し、ルールセットのステータス有効化も実施できたら
ルールの作成に移ります。

(10)ルール設定の定義

ルール名を記述して次へ進みます。

  • ルール名:Lambda-to-Discord

それ以外は画面の通りになっていればOK
※特に触らずともこの状態です

(11)受信者の条件の追加

何もせず次へ

(12)アクションの追加

新しいアクションの追加を押下し、以下アクションを追加します。
これまで作成したものを選択します。

  • AWS Lambda 関数の呼び出し
  • Amazon S3 バケットに配信
(13)レビュー

以下の画面を確認し、問題なさそうなら作成します。

(14)Lambdaへのアクセス許可追加

このポップアップが出た場合は「アクセス許可の追加」を押下します。

(15)ルールの作成確認

作成後の状態確認をします。
ルールセット/ルールいずれも有効になっていることを確認します。

※これが片方でも無効の場合は正常に動作しません

メールクライアントの転送設定

Gmailによる動作確認

今回はGmailを利用した転送設定を紹介していきます。
[左ペイン]-[ラベルの管理]-[タブ:メール転送とPOP/IMAP]-[転送先アドレスを追加]

以下の形式で転送先アドレスを設定します。

  • 構文:[適当な名前]+@+mail.blog.addache.jp
  • サンプル:gmail@mail.blog.addache.jp

適当な名前 は、英数字で構成さえしていれば本当になんでもいいです。
@ より後方は、本記事で作成したドメインを指定します。

※本人確認画面は省略します

以下のように確認リンクを送付した旨のメッセージが表示されます。

Discordへ通知が飛んできていたら成功です。

なお、Lambda経由でのSES転送メールには「本文」が含まれないので
Gmailの確認リンクをDiscordで直接受け取ることはできません。
※そのため、S3バケットへメールの原本を格納する構成を取っています

作成したS3バケットを開くと、以下のようにメール原本が格納されてます。

  1. 一番新しいファイルをダウンロード ※何度も操作するとこのようにゴチャります。。。
  2. DLしたファイルへ拡張子[.eml]を付与
  3. OutLookなどのメールソフトでファイルを開く

以下はThunderBirdで開いた例です。
途中のURLを伏せてますが、この確認リンクをクリックすると先へ進めます。
※本人確認などが発生します

Gmailへ戻りフィルタ設定で転送先を設定します。

注1) 本人確認済みにも関わらず、転送メールが設定できない場合は画面リロードするのが有効
注2) 転送先メールを設定したフィルタは、更新のたびに本人確認を要求されて少しうっとおしい

(補足)Gmailのフィルタ動作について

Gmailのフィルタによる自動転送は、新しく受信したメールが対象です。
既存メールを別のラベルへ移動したり、「一致するスレッドにもフィルタを適用する」を選択したりしても、過去に受信したメールは転送されません。
※上記のサンプル画像にも明記されています

Gmailでの動作確認の際は、フィルタ条件に一致するメールを新たに受信する必要があります。

hotmailなどのサービスを利用しているなら、そちらで転送確認を行ったほうが
実際の挙動に対する手応えがあると思います。

最後に

今回はAmazon SESとLambdaを利用して、
各種メールサービスで受信したメールをDiscordへ通知する仕組みを構築しました。

普段利用しているメールサービスを変更することなく、
必要なメールだけをDiscordへ集約できるのが本構成の特徴です。

Discordは通知専用とし、メール本文は従来どおり各メールサービスで確認します。

また、S3にメール原本を一時保存することで、Gmailの転送先確認メールのように
本文の確認が必要なケースにも対応できるようにしました。

メールの振り分けや転送設定はサービスごとに異なりますが、一度設定してしまえば
あとは普段どおりメールを利用するだけです。

重要なメールを見落とさないための仕組みとして、参考になれば幸いです。

最近だとAIにGmailを連携して重要なメールをキャッチアップする手法もあります。

ただ、筆者のGmailはあまり仕事で利用していないのでAIと連携するほどでもなく
このぐらいの固定通知設定ができれば十分だったりします。
※配達会社のお荷物お届けメールなどが拾えれば大体満足

この仕組みのいいところは、
通知先をDiscordに一本化しながら、メールサービスごとに同じ仕組みを展開できることです。

Gmailに限らず、転送機能を持つメールサービスなら同じSESの受信口を利用できるため、
通知対象を増やす際にもAWS側の構成を大きく変更する必要がありません。

コメント

タイトルとURLをコピーしました