sesとlambdaでメールをslackに通知してみよう
TRANSCRIPT
![Page 1: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/1.jpg)
SES と Lambda でメールを Slack に通知してみよう
2016 年 3 月 21 日木村健一郎
![Page 2: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/2.jpg)
名前:木村健一郎所属:株式会社コム・アンド・コムお仕事:技術に関することはなんでも好きな言語: perl好きな DB : PostgreSQL
![Page 3: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/3.jpg)
今日のお題: SES と Lambda でメールを Slack に通知してみよう
![Page 4: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/4.jpg)
Slack 使ってますか?
•チャットツールです•WEB ブラウザ、 iOS/Android/Windows/Mac アプリで使えます•API あります•詳しくは http://slack.com/ へ
![Page 5: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/5.jpg)
メール使ってますか?
•なんだかんだで使わざるを得ない重要なメールを携帯に飛ばすとかよくあるよね?
•監視システムからの通知もメールが基本最近は API 叩けたり、 slack プラグインがあることも
•できれば通知系は slack にまとめたいよね?
![Page 6: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/6.jpg)
メールの内容を slack に飛ばそう!
ぱっと思いつくレガシーなやり方
1.SMTP サーバを作る。例えば postfix 。2.受信するメールアドレスを作って、そこ宛のメールをコマンドに渡す3.コマンドにはメールが標準入力経由で渡されるので、頑張ってパースして slack に飛ばす
hoge: “ | /path/to/command”/etc/aliases にこんな感じで書く
![Page 7: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/7.jpg)
・・・超めんどくさい (´ ・ ω ・ `)
( 特にサーバのお守りなんてしたくない )
![Page 8: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/8.jpg)
やっぱ時代はサーバレスでしょ! ( `・ ω ・ ´)
( 言ってみたかった )
![Page 9: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/9.jpg)
構成インターネット
SES
メール
S3S3 に保存
イベント通知
メール読み込み
API 呼び出し
![Page 10: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/10.jpg)
1. S3 を設定する
受信したメールを保存する S3 を設定します。適当な名前でバケット作りましょう。
( )S3※ オブジェクトは Lambda に渡すためにしか使わないから、期限を設定して自動で消しましょう!
![Page 11: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/11.jpg)
{"Version": "2008-10-17","Statement": [
{"Sid": "GiveSESPermissionToWriteEmail","Effect": "Allow","Principal": {
"Service": ["ses.amazonaws.com"
]},"Action": [
"s3:PutObjectAcl","s3:PutObject"
],"Resource": "arn:aws:s3:::BUCKET_NAME/*","Condition": {
"StringEquals": {"aws:Referer": "ACCOUNT_NO"
}}
}]
}
Policy はこんな感じで。
![Page 12: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/12.jpg)
2. SES を設定する
受信するドメインを決めます。自分で持ってるドメインでサブドメイン作るなり、新しいドメイン取るなりでまず準備しましょう。
手順1.メールアドレスを登録する2.ドメインの verifyをする (Route53なら早いです )3.アクションを追加するS3に保存するので、先ほどのバケット名を設定します
![Page 13: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/13.jpg)
今更ですが、なんで S3 ?
なんで S3 経由?アクションに Lambda ってあるやん?
S3 使わないと、本文や添付ファイルが取れないから
(多分理由は、 Lanbda 呼び出すときに渡すデータがでかいと嫌ってことかと思います)
![Page 14: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/14.jpg)
3. Lambda ファンクション書くぜ!
今回は Python で書きます。理由は以下の通り。
1.メールを取り扱うライブラリが標準である2.Slack 連携のライブラリがある3.新しく使えるようになったから試してみたい4.matetsu さんの記事を参考にしたから
![Page 15: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/15.jpg)
下準備
Python2.7 のインストールは適当に。ワークディレクトリを作って、 slack 用のライブラリをインストールします。
%mkdir ses-slack%cd ses-slack%pip install slackweb -t ./
![Page 16: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/16.jpg)
コード書くぜ(1)
lambda_function.py というファイルで作ります。utf-8 で書きます。
# coding: utf-8from __future__ import print_functionimport boto3import jsonimport ConfigParserimport emailfrom email.parser import FeedParserfrom email.header import decode_headerimport slackweb
出だしはこんな感じで。
![Page 17: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/17.jpg)
コード書くぜ(2)
ハンドラーの前半。 S3 からメールを取得。
def lambda_handler(event, context): try: record = event["Records"][0] bucket_region = record["awsRegion"] bucket_name = record["s3"]["bucket"]["name"] mail_object_key = record["s3"]["object"]["key"] s3 = boto3.client('s3', region_name=bucket_region) mail_object = s3.get_object(Bucket = bucket_name, Key = mail_object_key) mail_body = '' try: mail_body = mail_object["Body"].read().decode('utf-8') except: try: mail_body = mail_object["Body"].read().decode('iso-2022-jp') except: mail_body = mail_object["Body"].read()
msg_object = email.message_from_string(mail_body)
![Page 18: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/18.jpg)
コード書くぜ(3)
ハンドラーの中盤。本文、サブジェクト、送信元を取得します。 if msg_object.is_multipart(): body = msg_object.get_payload()[0] else: body = msg_object try: body = body.get_payload(decode=True).decode(body.get_content_charset()) except: #iso-2022-jp なのに丸文字があるとき code = 'iso-2022-jp-2004' body = body.get_payload(decode=True).replace('\033$B', '\033$(Q').decode(code)
(d_sub, sub_charset) = decode_header(msg_object['Subject'])[0] if sub_charset == None: subject = d_sub else: subject = d_sub.decode(sub_charset) (d_from, from_charset) = decode_header(msg_object['From'])[0] if from_charset == None: mfrom = d_from else: mfrom = d_from.decode(from_charset)
![Page 19: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/19.jpg)
コード書くぜ( 4 )
ハンドラーの後半。エラーハンドリングします。 except: subject = u"Error!" body = u" メールを受信しましたが、エラーが発生しました。 " mfrom = u" 送信元不明 "
どうしてもおかしな形式のメールというのはあるものでして・・・
![Page 20: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/20.jpg)
コード書くぜ( 5 )
ハンドラーの終盤。いよいよ slack に流します。 inifile = ConfigParser.SafeConfigParser() inifile.read("./config.ini") attachments = []
attachment = { "fallback": u"From:%s\nSub:%s" % (mfrom,subject), "pretext": u“From:%s\nSub:%s" % (mfrom,subject), "color": "#aaaaaa", "text": body } attachments.append(attachment)
slack = slackweb.Slack(url=inifile.get('slack', 'hook_url')) slack.notify(attachments=attachments, channel=inifile.get('slack', 'channel'), username=inifile.get('slack', 'username'), icon_emoji=inifile.get('slack', 'icon_emoji'))
return "CONTINUE"
![Page 21: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/21.jpg)
コード書くぜ( 6 )
設定ファイルを config.ini という名前で準備します。[slack]hook_url = https://hooks.slack.com/services/***username = alert_botchannel = 流す先のチャンネル名icon_emoji = :guardsman:
hook_url は slack の設定から取得します。Web ブラウザでアクセスし、設定の「 Apps & Custom Integrations 」→「 Incoming WebHooks 」です。
![Page 22: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/22.jpg)
アップロードするよ!
zip でまとめます。%zip -r ses-s3-lambda-slack.zip config.ini lambda_function.py slackweb
で、これを管理コンソールからアップします
![Page 23: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/23.jpg)
S3 のイベント設定するよ!
先ほどの S3 バケットに更新イベントを追加します。Lambda の管理コンソールだけでなく、以下のように S3 の管理コンソールからも追加できます。
![Page 24: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/24.jpg)
先ほど設定したメールアドレスにメールを送ってみましょう。
動かないときは以下のようにちょっと修正してローカルで動かしてみる ( 引数にテキストファイルとして保存したメールを渡す ) とデバッグしやすいです。もしくは、 print すると CloudWatch のログに出力されるので print デバッグで。import sys
def lambda_handler(m): try: mail_object = email.message_from_string(m)
……
return "CONTINUE"
if __name__ == "__main__": if len(sys.argv)>1: raw=open(sys.argv[1]).read() else: print "no args" exit
lambda_handler(raw)
5 .試験するよ!
![Page 25: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/25.jpg)
6 .応用するよ!
ここまでできたら色々遊べますね。•キーワードをハイライトしたり色を変える•本文に応じて通知するメールを取捨選択する•Slack から返信もできるようにしてみる•添付ファイルも見れるようにしてみる•Twilio と連携して SMS も送ってみる
色々遊んでみましょう!
![Page 26: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/26.jpg)
7 .感想
• Lambda 超便利 (^o^)• SES はウィルスメールフィルタなどもあって便利• この組み合わせ、スロッティングとか考えなくていいし楽
ちん• もっと楽にデバッグできない?• Perl on Lambda マダー?
たぶん永久に来ない? (´ ・ ω ・ `)• Qiita にまとめてますのでコードはこちらを参考に
http://goo.gl/2m0dqK
![Page 27: SESとLambdaでメールをSlackに通知してみよう](https://reader035.vdocuments.pub/reader035/viewer/2022062523/5871252a1a28abe4448b5f05/html5/thumbnails/27.jpg)