SESで受信したメールをLambdaで別の宛先に転送してみた

SESで受信したメールを、別の宛先へ転送してみたいと思います。ここでは、AWS WorkMailやMTAは利用せず、SES + Lambda Functionで実装してみたいと思います。
2020.02.25

SESで受信したメールを、別の宛先へ転送してみたいと思います。ここでは、AWS WorkMailやMTAは利用せず、SES + Lambda Functionで実装してみたいと思います。

構成イメージ

SESでメールを受信し、受信をトリガーにLambda Functionを起動させ、SESの送信APIを利用して別の宛先に送信するといったシナリオです。

00

前提

  • メールアドレスに使用するドメインのネームサーバがRoute53で管理されていること
  • SESで有効な受信ルールセット(Active Rule Set)が存在しないこと

やってみた

メール保存バケット作成

受信メール保存用バケット(ここでは、test-ses-receiving-mail)を作成し、SESにそのバケットに対する書き込み権限を与えます。バケット名、アカウントIDについては環境にあわせ変更してください。

バケットポリシー

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowSESPuts",
            "Effect": "Allow",
            "Principal": {
                "Service": "ses.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::バケット名/*",
            "Condition": {
                "StringEquals": {
                    "aws:Referer": "アカウントID"
                }
            }
        }
    ]
}

Lambda Function作成

メールを転送するLambda Functionを作成します。 ここでは、受信したメールを読み込み、SESのAPIで送信処理のみ実装しています。

TransferMail

import os
import boto3
import logging

s3_client = boto3.client('s3')
ses_client = boto3.client('ses')
logger = logging.getLogger()
logger.setLevel(logging.INFO)
s3_bucket = os.environ['S3_BUCKET']
forward_to = os.environ['FORWARD_TO']

def send_mail(message):
    ses_client.send_raw_email(
        Source = forward_to,
        Destinations=[
            forward_to
        ],
        RawMessage={
            'Data': message
        }
    )

def lambda_handler(event, context):
    logger.info(event)
    #メッセージID取得
    message_id=event['Records'][0]['ses']['mail']['messageId']
    #メッセージIDをキーにS3オブジェクト(メール)取得
    response = s3_client.get_object(
        Bucket = s3_bucket,
        Key    = message_id
    )
    # Emlデータ取得
    raw_message = response['Body'].read()
    # メール送信
    send_mail(raw_message)

受信メールの保存用バケットと、転送先アドレスは環境変数に設定しています。

ドメイン検証

メールアドレスに使用するドメインの所有権を確認します。

SESコンソールより「Domains」-「Verify New Domain」をクリックします。

メールアドレスで利用するドメインを入力します。ここではses-receiving.nochan.workを設定し「Verify This Domain」をクリックします。

ドメイン検証用のレコードセットが表示されます。ここではネームサーバにRoute 53を利用しているので「Use Route 53」をクリックします。

「Email Receiving Record」にチェックを付与し「Create Record Sets」をクリックします。なお、Route 53のドメインのMXレコードは上書きされますので、ドメイン名に間違いがないかご注意ください。

ホストゾーンに先程表示されたレコードが追加されます。ステータスが「verified」になったことを確認します。

受信ルール作成

受信したメールの処理条件などを定義します。

「Rule Sets」-「Crate a Rule Set」をクリックします。

任意のルール名を入力し「Crate a Rule Set」をクリックします。

画面を更新すると、作成した受信ルールが有効化されていると思いますので、有効化されていることを確認し「View Active Rule Set」をクリックします。

「Create Rule」をクリックします。

ここでは、ユーザ名は指定せずドメイン名(ses-receiving.nochan.work)を入力し「Add Recipient」をクリックします。

ドメインの検証は済んでいますので「Next Step」をクリックします。

以下のアクションを指定し「Next Step」をクリックします。

  • Action…S3
  • S3 bucket…作成したバケット(ここでは、test-ses-receiving-mail)
  • Action…Lambda
  • Lambda function…作成したLambda Function(ここでは、TransferMail)

任意のルール名を入力し「Next Step」をクリックします。

設定内容を確認し「Create Rule」をクリックします。

作成したルールのステータスが「Enabled」になっていることを確認します。

SES送信設定(メールアドレス登録)

メールを送信する前に「From」アドレスの所有確認が必要になります。アカウントがサンドボックスにある場合は「To」アドレスも確認する必要がありますので、誰にでもメールを送信する際はサンドボックスの解除が必要になります。

今回はサンドボックスを解除せず実施しますので、「From」と「To」アドレスの2つの所有を確認します。

「Email Addresses」-「Verify a New Email Address」をクリックします。

利用するメールアドレスを入力し「Verify This Email Address」をクリックします。

指定したメールアドレスに検証要求メールが届きますので、リンクをクリックして承認します。

同様の手順で「From」、「To」2つのアドレスの所有を確認しました。

動作確認

受信用に設定したドメインに対してメールを送信して、指定した宛先にメールが送信されるか確認してみたいと思います。

SESでメール受信ができると、保存用バケットにメールが保存されます。

受信ルールで設定したLambda Functionが動作し、指定のアドレスにメールが転送されました。

さいごに

S3のPUTトリガーでLambda Functionを起動させても同じようなことができると思いましたが、今回はトリガーをSESに寄せてみました。誰かのお役に立てれば幸いです。

参考