SESで受信したメールからLambda(python)で添付ファイル(テキストファイル)を取得してみる

どうも!大阪オフィスの西村祐二です。

今回はSESで受信したメールをS3に保存し、そのメールに添付ファイルがあれば、
Lambdaを使って添付ファイルを取得し、別バケットへ保存してみたいと思います。

※本エントリーでは、添付ファイルの対象をテキストファイルのみとしております。
また、掲載しているプログラムはサンプルコードとして捉えてください。
本番で利用する場合は、事前検証及び、リトライ処理やエラー処理、
ファイル名が日本語であったときの処理など考慮してください。

処理の流れ

  1. SESで受信したメールをS3バケットに保存する
  2. S3をトリガーにLambda Functionが起動する
  3. Lambdaによってメールの添付ファイルを別バケットへ保存する

事前準備

SESでメール受信設定

下記ブログを参考にSESでメールを受信、受信したメールをS3に保存するように設定します。

[新機能]Amazon SES でメール受信が出来るようになりました!

Lambdaの設定

  • ランタイム:Python3.6
  • トリガー:S3(put) ※メールを受信するバケット
  • ロール設定:S3の権限を付与してください

処理の内容

eventから得られるメールの名前よりオブジェクトを取得し、pythonのemailライブラリで
メールに添付されているファイルを取得する。

import boto3
import base64
import email
import urllib.parse

print('Loading function')

s3 = boto3.resource('s3')

def lambda_handler(event, context):
    # Get the object from the event and show its content type
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
    try:
        response = s3.meta.client.get_object(Bucket=bucket, Key=key)
        email_body = response['Body'].read().decode('utf-8')
        email_object = email.message_from_string(email_body)
        
        for part in email_object.walk():
            # ContentTypeがmultipartの場合は実際のコンテンツはさらに中のpartにあるので読み飛ばす
            if part.get_content_maintype() == 'multipart':
                continue
            # ファイル名の取得
            filename = part.get_filename()
            print(filename)
            # ファイル名がなければ飛ばす
            if not filename:
                continue
            else:
                # メールフォルダ内のfileディレクトリに添付ファイルを保存する
                attach_data = part.get_payload(decode=True)
                bucket_source = s3.Bucket(bucket)
                obj = bucket_source.put_object(ACL='private', Body=attach_data,
                                        Key='file' + "/" + filename, ContentType='text/plain')

        return 'end'
    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

テスト

実際にSES宛にファイルを添付したメールを送信し、添付ファイルが別バケットに出力されるかテストしてみます。

利用するテキストファイル

添付するテキストファイルの本文には英語と日本語と記号が記載されています。

message
test


日本語テスト

記号テスト
!@#$%^&*()_+|~{}:”>?<`,./;’[]

一つのファイルを添付して送信してみる

▼SESへファイルを添付したメールを送信します。

2017-11-14_3_01_04

▼想定通り、メールが保存されているバケット内のfileバケットに添付ファイルが保存されています。

2017-11-14_3_08_08

S3からローカルにファイルをダウンロードし、中身を確認しても添付したファイルと同じであることがわかります。

複数ファイルを添付して送信してみる

▼メールに添付するファイル名を「ses-attach2.txt」「ses-attach3.txt」として、SESへ送信します。

2017-11-14_3_17_28

▼想定通り、添付した2つのファイルがメールがfileバケットに保存されています。

2017-11-14_3_19_25

さいごに

いかがだったでしょうか。
Lambdaを使って、SESで受信したメールから添付ファイルを取得してみました。
pythonのemailライブラリを使えば、ある程度容易に受信したメールの解析ができそうです。
誰かの参考になれば幸いです。