LambdaからSESで画像付きのメールを送信する

2019.06.04

こんにちは、サーバーレス開発部の岡です。
最近はチャットでのコミュニケーションが主流ですが実際の業務ではまだまだEメールも使いますよね。
今回はLambdaでS3から画像をダウンロードLambdaにファイルを保存、SESで送信までの実装方法をご紹介したいと思います。

boto3で添付ファイルを送信する場合はsend_raw_emailを使います。

ちなみに添付ファイルなしの場合はboto3のsend_emailで送信することができます。
こちらのブログで紹介していますので参考にしてください。

LambdaからSESを呼んでメール送信をサクッと実装してみた

環境

  • Lambdaランタイム Python3.7(boto3)
  • Region: us-east-1(SES)

SESが東京リージョンで使えない為、SESのみバージニアリージョンを使います。

SESの設定

  • sandboxの解除申請(本番環境の場合)
  • 送信元アドレスorドメインをSESに登録

画像のダウンロード

添付する画像ファイルの情報はeventで渡せるようにします。
ダウンロード元のS3の環境は以下の通りです。

バケット名: attached_file_store
S3キー: 201906/angular.png

ダウンロード先は以下にします。
Lambda内の画像ダウンロード先: /tmp/img/201906

eventの中身

{
  "subject": "テスト",
  "text": "=========================\n\nテスト\n\n=========================",
  "file": {
    "path": "201906",
    "file_name": "angular.png"
  }
}

実行コード

import os
import logging
import boto3
from botocore.exceptions import ClientError
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication


# log
LOGGER = logging.getLogger()
LOGGER.setLevel(logging.INFO)

os.environ['TZ'] = 'Asia/Tokyo'
SRC_MAIL = 'from@test.email'
DST_MAIL = 'to@test.email'
SES_REGION = "us-east-1"
ses = boto3.client('ses', region_name=SES_REGION)
s3 = boto3.resource('s3')
BUCKET_NAME = 'attached_file_store'
bucket = s3.Bucket(BUCKET_NAME)


def send_raw_email(source, to, subject, body, img_absolute_path):
    LOGGER.info('send_raw_email: START')

    msg = MIMEMultipart()

    msg['Subject'] = subject
    msg['From'] = SRC_MAIL
    msg['To'] = DST_MAIL
    body_msg = MIMEText(body, 'plain')
    msg.attach(body_msg)

    att = MIMEApplication(open(img_absolute_path, 'rb').read())
    att.add_header('Content-Disposition','attachment',filename=os.path.basename(img_absolute_path))
    msg.attach(att)

    try:
        response = ses.send_raw_email(
            Source=source,
            Destinations=[to],
            RawMessage={
                'Data':msg.as_string()
            }
        )
        return response

    except ClientError as e:
        LOGGER.error(e.response['Error']['Message'])
    else:
        LOGGER.info("Email sent! Message ID:"),
        LOGGER.info(response['MessageId'])

def mkdir(path):
    img_path = f'/tmp/img/{path}/'

    if os.path.exists(img_path) == False:
        os.makedirs(img_path)
    else:
        pass

def download_s3_file(s3_key):
    download_dst = f'/tmp/img/{s3_key}'
    bucket.download_file(s3_key, download_dst)
    return download_dst


def lambda_handler(event, context):
    print(event)
    subject = event.get('subject')
    image = event.get('file')
    message = event.get('text')
    try:
        path = image['path']
        file_name = image['file_name']

        # 画像ファイル置き場を作成
        mkdir(path)

        # S3から対象ファイルをダウンロード
        img_absolute_path = download_s3_file(path + '/' + file_name)

        # メール送信
        response = send_raw_email(SRC_MAIL, DST_MAIL, subject, message, img_absolute_path)

        return response
    except Exception as error:
        LOGGER.error(error)
        raise error
  • mkdir()でダウンロード先のディレクトリを作成
  • download_s3_file()でeventのfileで指定したファイルをダウンロード
  • SESのsend_raw_email()でメール送信

という流れになります。

参考

AWS SDKs を使用して raw E メールを送信する