「メール受信をトリガーになんらかの操作をしたい」ときに調べたときの調査結果

やりたいこと

メール受信をトリガーになんらかの操作をしたい

実現方法

SendGrid

SendGridでメールを受信することはできますか? – サポート

  • Parse Webhookを利用して、指定したドメイン宛のメールを指定したURLにPOSTできる。
  • POSTには受信したメールのヘッダ、本文、添付ファイルなどの情報が含まれる。このPOSTをアプリケーション側で受けることにより、メール受信をトリガとした処理を実行できる。
  • Parse Webhookを利用するには、Domain Whitelabel設定を行った上でメールを受信するドメインのDNSのMXレコードの修正が必要

SendGrid設定方法

  1. SendGrid登録
  2. Domain Whitelabel
  3. MX/CNAMEレコードを追加
  4. Inbound Parse設定
  5. POSTリクエストを受け取るアプリケーションを用意
  6. メール送信

1. Send GridのFreeプランを登録する(私の場合、Azureから登録しました)

2. [Send Grid] Domain Whitelabel 設定

Parse Webhook(Inbound Parse)を利用するためには、まずDomain Whitelabel設定が必要のため、以下の通りサブドメインを登録します。

3. [ドメイン設定] MXレコードとCNAMEを追加する。

Domain Whitelabl登録時に表示されるCNAMEと、MXレコードをご自身のドメイン管理サイト(お名前.com)に、以下3レコードを追加します。

はじめ、Domain Whitelabel設定を行ったときに、これを登録しろと言われるCNAMEを全部登録した後にMXレコードを追加しようとしたが、お名前.com側で追加できなかった。

CNAMEに登録するのは、s1._domainkey.XXXX, s2._domainkey.XXXXの2つだけでよい。

livedoor Techブログ : CNAMEの間違った使い方

4. [Send Grid] Inbound Parse設定

Settings > Inbound Parse 対象ドメインのメール受信後にどのURLに対してPOSTするかを設定する。

  • subdomainの部分は、「2.」で登録したドメインを登録する。

  • Destination URLにはPOST先のURLを指定する。

テスト時は後述するRequestBinngrokのURLを指定した。

5. POSTリクエストを受け取るアプリケーションを用意

Node.js(Express)の場合。

server.js

const express = require('express');
const cors = require('cors');
const port = 4000;
const app = express();
const multer = require('multer');
let upload = multer();

app.use(cors());

// HTTPリクエストを受け取る
app.post('/incoming', upload.fields([]), function (req, res) {
console.log(req.body.subject);
console.log(req.body.text);
res.sendStatus(200);
});

// サーバーを起動する部分
const server = app.listen(port, function () {
var host = server.address().address;
console.log('Example app listening at http://%s:%s', host, port);
});
node server.js

6.メール送信

例えば、sub.hoge.comとした場合、mail@sub.hoge.comにメール送信する。

確認方法

以下のリンクで紹介されているRequestBinというWebサービスを利用するのがよいです。

Webhookのデバッグ

その後、ローカルデバッグしたい場合は、ngrokを利用する。

ハマった点

multipart/form-dataとして扱わなければならないところを扱っていなかったため、request.bodyが取得できなかった。

今までrequestのデータが取れない場合は、だいたいbodyParserで解決していたので、今回も同様に考えていたらハマった。上記で紹介しているRequestBinを試してみたところ、multipart/form-dataで送られてきていたので判明した。

https://stackoverflow.com/questions/24543847/req-body-empty-on-posts

https://stackoverflow.com/questions/37630419/how-to-handle-formdata-from-express-4

Node.jsではmulterというライブラリを使うのが通例(?)っぽいので試してみたところ解決した。

const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const port = 4000;
const app = express();
const multer = require('multer');
let upload = multer();

app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));

// HTTPリクエストを受け取る部分
app.post('/incoming', upload.fields([]), function (req, res) {
console.log(req.body.subject);
console.log(req.body.text);
res.sendStatus(200);
});
// サーバーを起動する部分
const server = app.listen(port, function () {
var host = server.address().address;
console.log('Example app listening at http://%s:%s', host, port);
});

ngrok

$ ngrok 4000
Session Status                online
Version                       2.2.8
Region                        United States (us)
Web Interface                 http://127.0.0.1:4040
Forwarding                    http://xxxxxxxx.ngrok.io -> localhost:4000
Forwarding                    https://xxxxxxxx.ngrok.io -> localhost:4000

Connections                   ttl     opn     rt1     rt5     p50     p90
                              29      0       0.00    0.00    0.02    0.56

HTTP Requests
-------------

POST /incoming                 200 OK

参考