Amazon SESを使って独自ドメインのメールをGmailで受け取る(改良版)

やってみた

 Amazonアソシエイトでユーザー追加をしたときに送られてくる確認メールにDKIM-Signatureが2つ入っていて、前の記事のLambda関数では動作しなかったので、別のものを参考に作り直した。

参考にしたもの

  • https://gist.github.com/skylander86/d75bf010c7685bd3f951d2b6c5a32e7b
  • 3年前のものでいくつか動作しないところがあったので変更した
    • handler関数名をdefaultのlambda_handlerに変更
    • message_from_fileからmessage_from_stringに変更(StreamingBodyがうまく受け取れないので)
    • raw_mailをmessage_from_stringに合わせてstringに変更

Lambda関数

正規表現であちこちこねくり回すよりシンプルになった。

from email import message_from_string
import json
import logging
import os
import re

import boto3
from botocore.exceptions import ClientError

FORWARD_MAPPING = {
    'xxxxxxx@example.com': ['xxxxxxxx@gmail.com'],
}

VERIFIED_FROM_EMAIL = os.environ['VERIFIED_FROM_EMAIL']  # An email that is verified by SES to use as From address.
SES_INCOMING_BUCKET = os.environ['SES_INCOMING_BUCKET']  # S3 bucket where SES stores incoming emails.

s3 = boto3.client('s3')
ses = boto3.client('ses')

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


def lambda_handler(event, context):
    record = event['Records'][0]
    assert record['eventSource'] == 'aws:ses'

    o = s3.get_object(Bucket=SES_INCOMING_BUCKET, Key=record['ses']['mail']['messageId'])
    raw_mail = o['Body'].read().decode('utf-8')

    msg = message_from_string(raw_mail)

    del msg['DKIM-Signature']
    del msg['Sender']
    del msg['Return-Path']

    original_from = msg['From']
    del msg['From']

    msg['From'] = re.sub(r'\<.+?\>', '', original_from).strip() + ' <{}>'.format(VERIFIED_FROM_EMAIL)

    if not msg['Reply-To']: msg['Reply-To'] = original_from
    msg['Return-Path'] = VERIFIED_FROM_EMAIL
    msg_string = msg.as_string()

    for recipient in record['ses']['receipt']['recipients']:
        forwards = FORWARD_MAPPING.get(recipient, [])
        if not forwards:
            logger.warning('Recipent <{}> is not found in forwarding map. Skipping recipient.'.format(recipient))
            continue
        #end if

        for address in forwards:
            try:
                o = ses.send_raw_email(Destinations=[address], RawMessage=dict(Data=msg_string))
                logger.info('Forwarded email for <{}> to <{}>. SendRawEmail response={}'.format(recipient, address, json.dumps(o)))
            except ClientError as e: logger.error('Client error while forwarding email for <{}> to <{}>: {}'.format(recipient, address, e))