SendGridのEmail ActivityをS3に保存してAthenaでクエリする
SendGridにはEmail Activityというアカウントとサブユーザーに関連付けられた最近のメール関連のアクティビティイベントのスナップショットを表示する機能があります。
メールを送信した、受信者のメールボックスに届いた、バウンスした、スパムレポートされたなどの情報を日付やメールアドレスで検索できます。
Email Activityは、freeプランの場合だと3日間となっています。
有料のプランでも最大7日ですが、アドオンを購入することで30日まで保存できるようになります。
さらに古いイベントを検索したい、他のデータと組み合わせて分析したいといったことが出てくることもあるかと思います。
そういった時はEvent Webhook
を利用して外部のストレージ等にデータを保存することで可能になります。
イベントは、メールがSendGridおよびメールサービスプロバイダーによって処理されるときに生成されます。 イベントには、
- 配信イベント(Processed, Dropped, Delivered, Deferred, Bounce, Blocked)
- エンゲージメントイベント(Open, Click, Spam Report, Unsubscribe, Group Unsubscribe, Group Resubscribe)
の2種類があります。
SendGridでEvent Webhook
の設定をするには、Settings->Mail Settings->Event Webhook
をクリックし、
HTTP Post URLの入力とHookしたいEventを設定します。
やってみる
LambdaとAPI Gatewayを使ってHTTP Post URLを作り、Event Webhookを処理できるようにします。
LambdaでEvent Webhookのペイロードを処理する
まず、Lambdaでeventを受信できるか確認してみます。
関数を作成し、以下のコードを保存します(node12.xのランタイムを使用した例です)
exports.handler = function(event, context) { console.log('--- sendgrid event start ---'); console.log(event); console.log('--- sendgrid event end ---'); };
POSTで受ける口はAPI Gatewayにします。関数のトリガーに追加します。
HTTP APIにしてみました。JWTオーソライザーを使った方が良いですが、今回の検証ではオープンにして追加しています。
追加が完了した後、APIのエンドポイントをコピーします。
コピーしたURLをSendGridのEvent WebhookのURLに指定します。
Test Your Integration
のボタンをクリックし、正常にサンプルイベントが送信されたかどうか確認します。
※ Event Webhook StatusをEnableにしましょう
サンプルイベントが送信されたかどうかはcloudwatch logsで確認できます。
サンプルコードでevent
を全て出力するようにしていたので、上記のようにログが吐かれているはずです。
ここまで確認できたら、Sendgrid側の設定を保存します。
全てのイベントをwebhookの対象にしました。
実際にメールを送ってみる
SendGridからのイベント情報はbodyに格納されるので、Lambdaの関数を以下のように編集します。
exports.handler = function(event, context) { console.log('--- sendgrid event start ---'); console.log(event["body"]); console.log('--- sendgrid event end ---'); };
実際に何かメールを送信して、Cloudwatch Logsに出力されるか確認します。
設定が正しいと、Processed
やOpen
などのイベントがログに出力されることを確認できるはずです。
S3に保存するようにLambdaを編集
きちんとWebhookを受信できることが確認できたので、その内容をS3に保存します。 バケットは何か用意し,Lambdaの実行ロールにs3へのアクセス権限を付与しておきましょう。
uuidを使用するので
npm install uuid
を実行してから、node_modulesを含んだ状態で関数をデプロイします。
関数は以下のように編集します。
const AWS = require('aws-sdk') var s3Bucket = new AWS.S3( { params: {Bucket: "<<Your Bucket>>"} } ); var uuid = require('uuid'); exports.handler = (event, context, callback) => { console.log('--- sendgrid event start ---'); console.log(event.body) console.log('--- sendgrid event end ---'); let webhook_body = ""; let event_object = JSON.parse(event.body); event_object.map((item)=>{ webhook_body = webhook_body + JSON.stringify(item) + "\n" }) var filePath = "<<Path to Object>>/"+ uuid.v4(); var data = { Key: filePath, Body: webhook_body }; s3Bucket.putObject(data, function(err, data){ if (err) { console.log('Error uploading data: ', data); callback(err, null); } else { console.log('Successfully uploaded the response'); callback(null, data); } }); };
<<Your Bucket>>
と<<Path to Object>>
は自身の環境に合わせて変更してください。
関数をデプロイ後にメールを送信すると、以下のようにバケットにファイルが保存されます。
Athenaでクエリしてみる
S3にjsonファイルとしてイベントを保存したので、Athenaでクエリできるようにしていきます。
テーブルの作成が必要になりますが、AWS Glueのクローラーを使ってテーブルを作ります。
ファイルを保存したS3バケットを対象にしたクローラーを作成します。
このようなスキーマをもったテーブルが作成されます。
Athenaのコンソールでクエリしてみます。
SELECT * FROM "sendgrid"."sendgrid_webhooks" limit 10;
上記のような感じで10件出力されていることが確認できます。
eventやemail,ipなんかで条件を絞って検索することも可能ですね。
s3にファイルとして保存しておくことで、過去のイベントを検索したり、他のデータと組み合わせて分析することが容易になります。 SendGridのEmail Activityが30日まででは要件を満たせないといった方はこのような方法を試す価値はあるのではないかと思います。