SendGridのアクティビティログを収集してみた

まえがき

はじめまして、鮠河(はやかわ)と言います。

初めてブログを書くことになったのですが、今回はとりあえず最近実装したSendGridのアクティビティログの取得についてまとめていきたいな~と思います。

SendGridとは?

まずはSendGridとはなにかから説明したいと思います。
SendGridとはメール配信サービスです。
クラウドサービスなので登録すればすぐに使えてライブラリも豊富なので実装しやすいです。
また、公式ブログもあり導入手順など色々な情報が上がっているので便利なので、システムのメールサービスとして使用させてもらっています。
興味のある方は参照して見てください。
https://sendgrid.kke.co.jp/

動作環境

今回はSendGridからのリクエストをAWSのAPI Gatewayで受信しLambdaで処理を行い、S3にJSONファイルとして保存していきたいと思います。

動作完了は下記の通りです。

  • SendGrid
  • AWS API Gateway
  • AWS Lambda(nodejs 14.x)
  • AWS S3

Lambdaの作成

まずはLambdaを作成していきたいと思います。

AWS マネジメントコンソールから「Lambda」を選択し、「関数の作成」をクリックします。

「一から作成」を選択し、基本的な情報を入力し「関数の作成」をクリックし関数を作成していきます。
実行ロールに関しては各自の環境により変更してください。

  • 関数名:sendgrid-webhook
  • ランタイム:Node.js 14.x
  • アーキテクチャ:x86_64

関数を作成したらコードを入力していきます。
ソースは下記となります。受信した内容からイベント別のフォルダの中に本日の日付のフォルダを作成し、ランダム生成した文字列をファイル名として保存していきます。

S3のバケットは事前に作成してあるもとのします。

必要なモジュールは下記の通りです。
これらはレイヤーとしてアップロードしており、レイヤー追加しています。

  • moment:2.24.0
  • uuid:7.0.2
  • @sendgrid/eventwebhook:7.4.5
const BUCKET_NAME = 's3_bucket';

const aws = require('aws-sdk');
const s3 = new aws.S3();
const uuid = require('uuid');
const moment = require('moment');
const {EventWebhook, EventWebhookHeader} = require('@sendgrid/eventwebhook');

const verifyRequest = function (publicKey, payload, signature, timestamp) {
    const eventWebhook = new EventWebhook();
    const ecPublicKey = eventWebhook.convertPublicKeyToECDSA(publicKey);
    return eventWebhook.verifySignature(ecPublicKey, payload, signature, timestamp);
};

exports.handler = async (event, context, callback) => {
    console.log('--- sendgrid event start ---');
    console.log(event);

    const activities = [
        'open',
        'click',
        'delivered',
        'bounce',
        'deferred',
        'dropped'
    ];
    
    // bodyの中身をJSONに変換し、リストに追加
    let event_object = JSON.parse(event.body);
    for(let activity of activities) {
        let webhook_body = '';
        
        // 対象のイベントのみを抽出して格納
        event_object.filter(x => x.event === activity).map((item) => {
            webhook_body = webhook_body + JSON.stringify(item) + '\n';
        });
        
        // 対象のイベントが存在しない場合は次のアクティビティへ
        if(webhook_body === '') {
            continue;
        } else {
            // アクティビティごとのファイルパスを設定
            const filePath = moment().format('YYYYMMDD') + '/' + activity + '/'+ uuid.v4() + '.json';
            let params = {
                Bucket: BUCKET_NAME,
                Key: filePath,
                Body: webhook_body
            };

            try {
                var data = await s3.putObject(params).promise();
                console.log('Successfully uploaded the ' + activity + ' response:' + filePath);
                console.log(data);
            } catch (error) {
                console.log('Error uploading ' + activity + ' data: ', data);
                console.log (error);
            }
        }
    };
    console.log('--- sendgrid event end ---');
};

API Gatewayの設定

API Gatewayの設定をしていきます。

AWS マネジメントコンソールから「API Gateway」を選択し、「APIを作成」をクリックし、次の画面の
「APIタイプを選択」で「HTTP API」の構築をクリックします。

「統合」から「Lambda」を選択し、上記で作成したLambda関数を選択します。
「API名」はここでは「sendgrid_webhook」とします。

続いて、「ルートを設定」「ステージを定義」はそのまま「次へ」をクリックし最後に「作成」をクリックして完了です。

以上でAWS側の設定は完了です。

SendGridの設定

AWS側の設定が完了したら、今度はSendGridでWebhookの設定をしていきます。

https://app.sendgrid.com/loginからSendGridへログインし、サイドバーから「Mail Settings」をクリックし一覧から
「Event Webhook」をクリックします。

クリックするとEvent Wenhookの設定画面が表示されますので、値を入力していきます。

  • Authorization Method:None
  • HTTP Post URL:作成したAPI GatewayのURL
  • Event to be POSTTed to your URL:欲しいイベント情報にチェック

これで設定は完了です。
連携前に一度テストしたい場合は、「Test Your Integration」をクリックするとテスト用リクエストが送信されます。
Lambdaのモニタリングからログを確認するとリクエスト受信した結果があります。

まとめ

今回はSendGridのログをS3に保存していく方法を書きました。
ログ情報はJSON形式で保存されているので、ログをAthenaに取り込み集計すれば色々と約に立つと思います。
例えばSendGridはカスタム変数が設定出来るので、送信時に特定のIDを設定しておけばどのメールの開封率が多かったかなども算出出来るのではないでしょうか?
保存していくだけでは意味がないので、これを活用する内容を実施して続きを書ければと思います。

最後まで読んで頂きありがとうございました。

参考文献