🐙
AWSのLambdaでお問い合わせAPIを作る
構成要素
DynamoDB: お問い合わせデータ保存用のDB
Lambda: 処理を記載
APIGateway: Lambdaのエンドポイント
目標
お問い合わせをされた受けた時にDBにレコードをのこす
お問い合わせをした人にお問い合わせを承ったことをメールで知らせる
管理人にお問い合わせがあったことをメールで知らせる
Lambdaの記述
いったん全部
import json
import boto3
import os
# for date and time
import re, datetime
# for generate id
import random, string
""" DynamoDB """
from boto3.dynamodb.conditions import Key
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(os.environ["DB_NAME"])
""" Email """
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from_email = os.environ["FROM_MAIL"]
smtp_user = os.environ["SMTP_USER"]
password = os.environ["MAIL_PASS"]
host = os.environ["HOST"]
email_port = 587
subject_user = os.environ["SUB_USER"]
subject_owner = os.environ["SUB_OWNER"]
message_user = os.environ["MESS_USER"]
message_owner = os.environ["MESS_OWNER"]
my_usual_email = os.environ["USUAL_MAIL"]
#########################################
# functions #
#########################################
# generate id
def gen_id():
random_ = [random.choice(string.ascii_letters + string.digits + '-' + '_') for i in range(4)]
id_ = "".join(random_)
return id_
# generate date and time with int
def gen_datetime():
str_datetime = "{}".format(datetime.datetime.now())
str_date, str_time = str_datetime.split(" ")
lst = [
int(str_date.replace("-", "")),
int(re.sub(r'\.[\d]*', '', str_time.replace(":", "")))
]
return lst
# send email
def sending_user(name, mail, content, category):
content = re.sub('\r|\n\r\|\n', '<br>', content)
message = message_user.format(from_=from_email, user_=name, content_=content, category_=category)
msg = MIMEMultipart('alternative')
#msg = MIMEText(message, "html")
msg["Subject"] = subject_user
msg["To"] = mail
msg["From"] = from_email
msg_bod = MIMEText(message, "html")
msg.attach(msg_bod)
message_ow = message_owner.format(mail_=mail, user_=name, content_=content, category_=category)
msg_owner = MIMEMultipart('alternative')
msg_owner["Subject"] = subject_owner
msg_owner["To"] = from_email
msg_owner["From"] = from_email
msg_owner_bod = MIMEText(message_ow, "html")
msg_owner.attach(msg_owner_bod)
server = smtplib.SMTP(host, email_port)
server.ehlo()
server.starttls()
server.ehlo()
# AWS SES
server.login(smtp_user, password)
# for user
server.sendmail(from_email, mail, msg.as_string())
# for owner
server.sendmail(from_email, my_usual_email, msg_owner.as_string())
server.close()
#########################################
# operations #
#########################################
def operation_scan():
scanData = table.scan()# get all
items = scanData['Items']
print(items)
return scanData
def operation_put(id, name, mail, content, category):
date = gen_datetime()[0]
time = gen_datetime()[1]
putResponse = table.put_item(
Item = {
'id': id,
'name': name,
'mail': mail,
'content': content,
'category': category,
'date': date,
'time': time,
}
)
if putResponse['ResponseMetadata']['HTTPStatusCode'] != 200:
print(putResponse)
else:
print(200, putResponse)
sending_user(name, mail, content, category)
return putResponse
#########################################
# handler #
#########################################
def lambda_handler(event, context):
OperationType = event['OperationType']
try:
if OperationType == "PUT":
Id = gen_id()
Name = event["Keys"]["name"]
Mail = event["Keys"]["mail"]
Content = event["Keys"]["content"]
Category = event["Keys"]["category"]
return operation_put(Id, Name, Mail, Content, Category)
elif OperationType == "SCAN":
return operation_scan()
except Exception as e:
print("Erro Exception.")
print(e)
詳細
DynamoDB(問い合わせ情報の保存用)
""" DynamoDB """
from boto3.dynamodb.conditions import Key # 今回は使ってないが、キーでフィルターを書ける等に使う
dynamodb = boto3.resource('dynamodb') # dynamodbへのアクセス
table = dynamodb.Table(os.environ["DB_NAME"]) # tableへのアクセス
メール設定(問い合わせが来たら自動で返信 & 持ち主の普段使いのメールに通知)
""" Email """
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from_email = os.environ["FROM_MAIL"] # 送り元のメールアドレス(今回はAWS SESを使用)
smtp_user = os.environ["SMTP_USER"] # AWS SESで確かめてそれを使用(gmailならメールアドレスでOK)
password = os.environ["MAIL_PASS"] # AWS SESで確かめてそれを使用
host = os.environ["HOST"] # AWS SESので確かめてそれを使用(email-smtp.<region>.amazonaws.com)
email_port = 587
subject_user = os.environ["SUB_USER"] # ユーザーに送る件名
subject_owner = os.environ["SUB_OWNER"] # オーナーに送る件名
message_user = os.environ["MESS_USER"] # ユーザーに送る本文
message_owner = os.environ["MESS_OWNER"] # オーナーに送る本文
my_usual_email = os.environ["USUAL_MAIL"] # 普段使いのメールアドレス
実行する処理
下準備用関数
# generate id
# ランダム文字列を生成
# 今回はやってませんが、文字数intを引数にすると使い勝手が良いです
def gen_id():
random_ = [random.choice(string.ascii_letters + string.digits + '-' + '_') for i in range(4)]
id_ = "".join(random_)
return id_
# generate date and time with int
# 現在時刻のdateとtimeのリストを生成
def gen_datetime():
str_datetime = "{}".format(datetime.datetime.now())
str_date, str_time = str_datetime.split(" ")
lst = [
int(str_date.replace("-", "")),
int(re.sub(r'\.[\d]*', '', str_time.replace(":", "")))
]
return lst
メール送信用の関数
# send email
def sending_user(name, mail, content, category):
content = re.sub('\r|\n\r\|\n', '<br>', content) # 入力された内容の改行文字を置換する
# ユーザーへのメール送信
message = message_user.format(from_=from_email, user_=name, content_=content, category_=category) # 本文を入力内容に合わせてフォーマット
msg = MIMEMultipart('alternative')
msg["Subject"] = subject_user # 件名
msg["To"] = mail # 宛先
msg["From"] = from_email # 送信元
msg_bod = MIMEText(message, "html")
msg.attach(msg_bod)
# 管理人へのメール送信 (上とほぼ同じ)
message_ow = message_owner.format(mail_=mail, user_=name, content_=content, category_=category)
msg_owner = MIMEMultipart('alternative')
msg_owner["Subject"] = subject_owner
msg_owner["To"] = from_email
msg_owner["From"] = from_email
msg_owner_bod = MIMEText(message_ow, "html")
msg_owner.attach(msg_owner_bod)
# smtpサーバーを起動
server = smtplib.SMTP(host, email_port)
server.ehlo()
server.starttls()
server.ehlo()
# AWS SES
server.login(smtp_user, password) # smtpサーバーにログイン
# for user
server.sendmail(from_email, mail, msg.as_string()) # ユーザーにメールを送る
# for owner
server.sendmail(from_email, my_usual_email, msg_owner.as_string()) # 管理人にメールを送る
server.close() # smtpサーバーを閉じる
アクセスがあった際の処理
def operation_put(id, name, mail, content, category):
date = gen_datetime()[0] # 現在の日付
time = gen_datetime()[1] # 現在の時刻
putResponse = table.put_item( # tableの作成
Item = {
'id': id, # 引数で受け取る
'name': name, # 引数で受け取る
'mail': mail, # 引数で受け取る
'content': content, # 引数で受け取る
'category': category, # 引数で受け取る
'date': date,
'time': time,
}
)
if putResponse['ResponseMetadata']['HTTPStatusCode'] != 200:
print(putResponse)
else:
print(200, putResponse)
sending_user(name, mail, content, category) # 問題がなければメールを送信
return putResponse
試す
curl -X POST '<API Gatewayのエンドポイント>' -d '{"OperationType": "PUT", "Keys": {"name": "userA", "mail": "<your email>", "content": "This is sample", "category": "sample"}}'
これでメールが送受信されてデータも追加されてるはずです
curl -X POST '<API Gatewayのエンドポイント>' -d '{"OperationType": "SCAN"}'
でレコードを全部見れます
余談
NoSQLであることを考えるとpartition keyをmailにした方がイケてる気がする
アドバイスや疑問点等ありましたらコメントよろしくお願いいたします。
Discussion