やりたいこと(part1,2と同様)
下記工程を人の手でやっていたところを自動化したいそう。
なんとなくAWSだけで構築できそうなので考えてみた
- SESでSCVファイルが添付されたメールを受信する
- 受信したメールをS3に格納
- S3格納をトリガーにLambda発火
- LambdaでCSVファイルの加工を行う。(記入ミスがある場合SESを使用して返信)
- 加工したCSVファイルをS3に格納
- 時間発火(EventBridge+Lambda)でCSVファイルをserverに送信(FTPかな?)
って感じです。
とりあえずやってみよう。笑笑
とりあえずLambdaでメールを送信できるようにする
この部分!!
一旦メールを送れるようにしてから、ファイルを添付する方法を考えようと思います。
とりあえずロール追加。
あまりFullAccessは良くないと分かっていても検証ではやってしまいますね、
Lambda+SESでメールを送信するためには、送信先のメールアドレスの認証が必要になるそうです。
「SES」→「検証済みID」→「IDの作成」からメアドの認証をします。
IDタイプ:Eメールアドレス
Eメールアドレス:送信したいメールアドレス
part2で作成したLambdaにメールを送信するコードを追記します。
メール受信したら返信するだけのコードです。
client.send.emailでメールの件名とか文を作成してますね。
import boto3
import base64
import email
import urllib.parse
import json
from logging import getLogger, INFO
logger = getLogger(__name__)
logger.setLevel(INFO)
s3 = boto3.resource('s3')
#追加-------------------------------------------------------------------------------------------------
#メアド
SRC_MAIL = "送信元メールアドレス"
DST_MAIL = "送信先メールアドレス"
REGION = "SESのリージョン"
#メール送信
def send_email(source, to, subject):
client = boto3.client('ses', region_name=REGION)
response = client.send_email(
Source=source,
Destination={
'ToAddresses': [
to,
]
},
Message={
'Subject': {
'Data': subject,
},
'Body': {
'Text': {
'Data': "返事やで~",
},
}
}
)
return response
#ここまで-------------------------------------------------------------------------------------------------
def lambda_handler(event, context):
print("--------- logger.info の出力 ---------")
logger.info(json.dumps(event))
# S3のデータ取得
bucket = event['Records'][0]['s3']['bucket']['name']
key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
messageid = key.split("/")[1]
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():
print("maintype : " + part.get_content_maintype())
if part.get_content_maintype() == 'multipart':
continue
# ファイル名の取得
attach_fname = part.get_filename()
print(attach_fname)
# ファイルの場合
if attach_fname:
# fileに添付ファイルを保存する
attach_data = part.get_payload(decode=True)
bucket_source = s3.Bucket(bucket)
bucket_source.put_object(ACL='private', Body=attach_data,
Key='file' + "/" + attach_fname, ContentType='text/plain')
#追加--------------------------------
#メール送信
e = "ミスやで~"
r = send_email(SRC_MAIL, DST_MAIL, e)
#ここまで----------------------------
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
メールを送信して返事が来るか試してみる
メールにファイルを添付して送信する
さっき作成したLambdaに追記していきます!
ファイルを添付して送信するときの注意点!!
・メール送信にはclient.send_raw_email()を使用しないと、ファイルを添付できない。
・LambdaではS3から直接ファイルを取得して添付ファイルにすることができない。
→Lambdaのtmp/配下に一度保存してからファイルを添付する流れ。
import boto3
import base64
import email
import urllib.parse
import json
import os
from logging import getLogger, INFO
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
logger = getLogger(__name__)
logger.setLevel(INFO)
s3 = boto3.resource('s3')
#メアド
SRC_MAIL = "送信元メールアドレス"
DST_MAIL = "送信先メールアドレス"
REGION = "SESのリージョン"
#メール送信
def send_email(source, to, subject):
client = boto3.client('ses', region_name=REGION)
#変更-----------------------------------------------------------------------
msg = MIMEMultipart()
filepath="/tmp/test.csv"
part = MIMEApplication(open(filepath, "rb").read())
part.add_header("Content-Disposition", "attachment", filename="test.csv")
msg.attach(part)
part = MIMEText("添付ファイルやで~")
msg.attach(part)
response = client.send_raw_email(
Source=source,
Destinations=[
to
],
RawMessage={
"Data": msg.as_string(),
},
)
#ここまで------------------------------------------------------------------
return response
def lambda_handler(event, context):
print("--------- logger.info の出力 ---------")
logger.info(json.dumps(event))
# S3のデータ取得
bucket = event['Records'][0]['s3']['bucket']['name']
key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
messageid = key.split("/")[1]
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():
print("maintype : " + part.get_content_maintype())
if part.get_content_maintype() == 'multipart':
continue
# ファイル名の取得
attach_fname = part.get_filename()
print(attach_fname)
# ファイルの場合
if attach_fname:
# fileに添付ファイルを保存する
attach_data = part.get_payload(decode=True)
bucket_source = s3.Bucket(bucket)
bucket_source.put_object(ACL='private', Body=attach_data,
Key='file' + "/" + attach_fname, ContentType='text/plain')
#追加-------------------------------------------------
#tmp配下に保存
with open("/tmp/test.csv", "a") as attach_data:
print("Write data to testFile", file=attach_data)
#ここまで---------------------------------------------
#メール送信
e = "ミスやで~"
r = send_email(SRC_MAIL, DST_MAIL, e)
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
添付ファイルが送信できるか確認する
先ほどと同様にメールを送信してみた。
終わり!!!!!!!!!!
後はLambda上でCSVファイルをいい感じにして(openpyxlとかかな?)記載ミスがあればSESで返信、
正しければS3のfile/配下に格納という動作を付け加えれば、当初やりたかった機能を実装可能かと。
Eventbridge + Lambdaの検証はそこら中に転がっているので今回はパスしました。笑笑
(Azure Functionsなら時間実行とか一瞬やのにな~とか思いながら)
とりあえずpart1~3に分けて技術ブログというものを書いてみました。
初めてのことなので、文章がわかりづらかったり理解が間違っていたりすることがあるかもしれないですが
やり続けないと成長しないと思うのでこれからも少しずつ続けていきます。
これからも何か面白そうなものがあれば検証してみます〇