SESを設定することでメール送受信が可能になります。ここでは受信したメールをS3に保存し、更に中身を転送してみます。
SES
ここではオレゴンのリージョンを選択します。認証済みドメインであればどんなメールアドレスでも使えます。ドメインの認証方法は
などを参照。
認証済みドメインを用いて、SESでメール受信する際にS3へ保存するトリガーを設定します。詳細なやり方は
に倣ってできます。
S3
メールを保存するためのバケットを用意します。LambdaのIAMで参照出来るようにプロパティでバケットポリシーを設定(Principalを"*"とか設定すればOK)。
この時点で、SESで認証済みのドメインにメールを何かしら送信すればS3に内容が保存されます。実際に試してみると、
このようになるはずです。
Lambda(Python)
S3にメールが保存されたというトリガーを設定してその都度Lambdaの処理を走らせるようにfunctionを作成します。
function
上画像の通りに設定。
ここではS3から保存されたメールのオブジェクトを取得→中身を解析→SESで送信の流れで処理を書きます。解析でやることは主にread()したあとにsubject, body(plain text), body(html), fromの中身を取得することです。html形式とplain text形式の両方が含まれます(相手が対応していない場合はhtmlはないかもしれません)。
メール転送はsend_mailだけ、中身は単純です。ここで注意しないといけないのは、replyおよびSourceにはSESで認証済みドメインしか使えないということ。このため、もしfrom情報を含めたければsubjectかbodyのどちらかに仕込むことになります。
コードは下記。
code
from __future__ import print_function import json import urllib import base64 import boto3 s3 = boto3.client('s3') EMAIL_TO = "送信先アドレス" def send_mail(from_address, reply, subject, body, html_body): client = boto3.client('ses', region_name='us-west-2') client.send_email( Source="noreplyなど、送信専用アドレス", Destination={ 'ToAddresses': [ EMAIL_TO, ] }, Message={ 'Subject': { 'Data': subject, }, 'Body': { 'Text': { 'Data': 'from: ' + from_address + '\n' + 'body: ' + body + '\n' + 'html_body: ' + html_body, }, } }, ReplyToAddresses=[ reply, ], ReturnPath="noreplyなど、送信専用アドレス" ) def lambda_handler(event, context): bucket = event['Records'][0]['s3']['bucket']['name'] key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key'].encode('utf8')) try: response = s3.get_object(Bucket=bucket, Key=key) mail = response['Body'].read().replace('\n','').replace('\r','') from_address = mail.split('envelope-from=')[1].split(';')[0] subject = mail.split('Subject: ')[1].split('To: ')[0] body = base64.b64decode(mail.split('base64')[1].split('--')[0]) html_body = base64.b64decode(mail.split('base64')[2].split('--')[0]) reply = "noreplyなど、送信専用アドレス" send_mail(from_address, reply, subject, body, html_body) except Exception as e: print(e) print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket)) raise e
以上です。細かく解説すると、
bucket = event['Records'][0]['s3']['bucket']['name']
でバケット名を、
key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key'].encode('utf8'))
でファイル名を取得しています。LambdaのトリガーにS3を設定した場合必ずこれで取得できる構造になっています。
肝心の内容は
response = s3.get_object(Bucket=bucket, Key=key) mail = response['Body'].read().replace('\n','').replace('\r','')
でメールオブジェクトを読み取ったあと、それぞれ
from_address = mail.split('envelope-from=')[1].split(';')[0] subject = mail.split('Subject: ')[1].split('To: ')[0] body = base64.b64decode(mail.split('base64')[1].split('--')[0]) html_body = base64.b64decode(mail.split('base64')[2].split('--')[0])
で送信元、タイトル(subject)、本文(body)、本文HTMLの4つを取得しています。元々のメールオブジェクトの中身は改行付きで1つの文字列として扱っておりわかりづらいので、mail = の行で改行を削除しています。そのうえで、ほしい情報を前後の文字列を見てsplit関数でうまいこと取り出しています。ゴリ押しですね...
S3のメールをダウンロードして中身のテキストを確認するとわかりますが、bodyの文字列がbase64エンコードされています。これをbase64デコードするために
base64.b64decode
を用いています。そのため、頭の
import base64
を忘れないこと!
これ以外の情報がほしければ、同様にsplitを使って文字列を切り出して取得する。
ここではS3にメールを保存しっぱなしにしていますが、メールが溜まってきたら容量は圧迫されるので、転送完了後に削除しちゃっても良いかもしれません。