SendGridのEventWebhookをAWS DynamoDBにいれるまで！

# はじめに
　SendGridのメールサービスを触ってみた。
　今回は、SendGridのSMTPリクエストとSendGrid EventWebhookを使いAWS側で受け取るところまでを紹介します。（ほんとは分析ようにKibanaまで行きたかったので、それは別で書こうと思います(\*^_^\*)

# SendGridとは
　SendGridは月間200億通を超えるメール配信を行い、世界のメール業界を支えています。
　ただ大量の配信をするだけでなく、配信したメールのアナリティクス機能も提供しています。
  トランザクションメールなんかも送れるので、利用の幅は広いですね。
　
# フロー
![1.png](https://qiita-image-store.s3.amazonaws.com/0/101531/d7b8fc1c-fdf7-c362-2294-69d47ebc0837.png)

# 実装
## SendGrid SMTP APIを使ったリクエスト
 SMTP APIではX-SMTPAPIヘッダを利用してメールのカスタム処理を指定できる。

```json:composer.json
{
    "minimum-stability" : "dev",
    "require": {
        "sendgrid/smtpapi": "~0.5",
        "swiftmailer/swiftmailer": "@stable"
    }
}
```

```php:sendMail.php
<?php
date_default_timezone_set('Asia/Tokyo');

require_once dirname( __FILE__ )."/lib/vendor/autoload.php";
use Smtpapi\Header;
// カスタムヘッダ例　名前の埋め込み
$to = array('kazuki.mitani+01@nijibox.co.jp', 'kazuki.mitani+02@nijibox.co.jp');
$from = "smtp-testmail@nijibox.co.jp";
$subject = "お久しぶり";
$body    = <<<EOF
%how%さんこんにちは！ \r\n
最近元気ですか？
EOF;
$substitution = array('三谷', '伊藤', '吉田');

//
$message = new \Swift_Message();
$message->setTo($to);
$message->setFrom($from);
$message->setSubject($subject);
$message->setBody($body);

// SMTP サーバーとの接続設定
$transport = \Swift_SmtpTransport::newInstance('smtp.sendgrid.net', 587);
$transport->setUsername('SENDGRID_USER');
$transport->setPassword('SENDGRID_PASS');
$mailer = \Swift_Mailer::newInstance($transport);

// ヘッダーの設定
$header = new Header();
$header->addSubstitution('%how%', $substitution);

$message_headers = $message->getHeaders();
$message_headers->addTextHeader(HEADER::NAME, $header->jsonString());

// 送信
try {
    $response = $mailer->send($message);
    print_r($response);
} catch(\Swift_TransportException $e) {
    print_r($e->getMessage());
}

```

## DynamoDBの作成
 DynamoDB
 ↓
 テーブル作成
 テーブル名：SendGridEvents
 プライマリーキー：sg_event_id 文字列

 で作成。

## Lambdaの設定
 受け取ったWebhookのポストをパースしてDynamoDBに入れるためのLambda Functionを作ります
 AWS Lambda
 ↓
 Create a Lambda function
 ↓
 元に使えそうなblueprintを選択。
 今回は、microserice-http-endpointを選択しました
 ↓
 設定
 name:SendGrid-EventWebhook
 Description:ダイナモDBに入れる
 Runtime:NodeJS
 ↓
 コードを書く

```js:lambda.js
var doc = require('dynamodb-doc');
var dynamo = new doc.DynamoDB();

exports.handler = function(event, context) {
  function logArrayElements(element, index, array){
    var params = {
      TableName: 'SendGridEvents',
      Item:element
    };
    dynamo.putItem(params, function (err, data) {
      if (err) {
        console.log(err, err.stack);
      } else {
        console.log(data);
      }
    });
  }
event.forEach(logArrayElements);
};
```

## API Gatewayの設定
 SendGridから飛んでくるWebhookの受け場所を作ります。
 AWS API Gateway
 ↓
 Create API
 ↓
 Create Method
 ↓
 POSTを選択
 Integration type:Lambda Function
 Lambda Region:ap-northeast-1(作製したLambdaのRegion)
 Lambda Function:SendGrid-EventWebhook(作製したLambdaのFunction名)

## EventWebhook到達確認
### INTEGRATION TESTING TOOL
 AWS側の設定はここまでで終了したので、疎通確認を行います。
 SendGridでは実際にメールを送らず、受け取り側のテストだけ行える”INTEGRATION TESTING TOOL”を提供しています。
 SendGrid
 ↓
 ログイン
 ↓
 ダッシュボード
 ↓
 Mail Settings
 ↓
 Event Notification
 ↓
 HTTP POST URL:API GatewayのURL
 ↓
 SELECT ACTIONSのすべてにチェックを付ける
 ↓
 保存してTestYourIntegrationをクリック。
 ↓
 DynamoDBの格納確認が出来たら成功！

### SMTPAPIを使った疎通確認
 先に作成したphpを実行して、メールリクエストを送ることで実際のWebhookを受け取れるか確認する。
 $ php sendMail.php
 ↓
 メールが届く
 ↓
 でもWebhookは届かない！！！

 状況確認
 1.INTEGRATION TESTING TOOLでは動く。
   ↓AWSは悪くない。
 2.SendGridのEventWebhookがそもそもAPIGatewayに到達していない。
   ↓SendGrid側が怪しい。
 3.ngrokを使ってEventWebhookのPOSTをローカルで受け取れた。
   ↓Webhookは送られている。

 結果：SendGridのWebhookの挙動が怪しい。

 ここで天から舞い降りた鶴の一声でAWS API GatewayのCustom Domain Namesを使用してみることに。
 ※https通信するためにAWSにCertificate body, Certificate private key, Certificate chainを登録する必要がある。

 AWS API Gateway
 ↓
 Custom Domain Names
 ↓
 Base path:api-gateway
 API:SendGrid-EventWebhook
 Stage:なし
 ↓
 https://使いたいドメイン/BasePath/Stage名/API名
 例： https://DOMAINNAME/api-gateway/prod/SendGrid-EventWebhook
 ↓
 SMTPAPIテスト
 ↓
 メールが届く
 ↓
 DynamoDBにデータが入る！成功！！

## まとめ
 SendGridと、使ってみたかったAWSに触れてみました。
 全く理解不能なところで詰まったり、悩んでた割にすんなりと設定出来たりといろいろ経験が出来ました。
 

おわり