Node.jsとPhantomJSを使ってメール受信処理を自動化する方法

この記事は Automatically Submit Data From Received Emails to an HTML Form Using Node and PhantomJS の抄訳です。

SendGridのInbound Parse Webhook機能は極めて強力で、そのユースケースは多様かつ幅広いものです。今回はSendGridのCommunity Developmentチームが、内部向けツールで利用しているメール受信をトリガとして自動的にHTTPのAPIをコールする方法をご紹介します。Inbound Parse Webhookを使う際のアイデアのご参考になれば幸いです。

背景

SendGridアクセラレートプログラムはメンターシップやリソースを提供することで世界中のスタートアップを支援しており、数多くのスタートアップがSendGridに連絡を取るためにWebサイト上のフォームから登録をしています。フォームからの登録があると、その情報が自動的にデータベースに登録され、チーム宛に自動的に通知メールが送信され、そのスタートアップに連絡が取れるようになっています。

一方、SendGridは数多くのトップレベルのアクセラレータとパートナー関係にあるので、彼らからも様々なスタートアップの情報がメールで送られてきます。

でも、これらは処理の観点からすると繋がっていません。(アクセラレータを経由すると)スタートアップがSendGridに連絡するのは簡単ですが、彼らの情報はSendGridのデータベースには登録されません。なぜなら、スタートアップがWebサイト上のフォームから入力していないからです。そこで、アクセラレータやスタートアップに負担をかけることなく、データベースに登録するための処理を自動化する仕組みを検討しました。難しかったのは、このデータベースに外部からデータを登録するための明示的なAPIがないという点です。

Inbound ParseとPhantomJSを導入する

SendGridは自動化が大好きです。そして、素晴らしいスタートアップがSendGridに連絡する手順をシンプルにしたかったので、この問題をInbound Parse Webhookを利用して解決することにしました。ここでの解決方法は、アクセラレータから送信されるスタートアップ関連情報を含むメールをパースし、PhantomJS(ヘッドレスなWebKit)を使ってWebサイト上のフォームから登録する処理を自動化するNode/Expressアプリケーションを作成する、というものでした。このアプリケーションを導入することで、スタートアップがWebサイト上のフォームから入力するのと全く同じ流れになります。

実装

このアプリケーションの実装はとてもシンプルです。まずはじめに、Inbound Parse Webhookの設定(Settings -> Inbound Parse配下)を行います。これで、設定したドメイン宛のメールの内容が指定したURLに自動的にPOSTされます。このPOSTリクエストをprocessEmailというエンドポイントにルートして処理します。

const ProcessEmail = require('./controllers/process-email');
const multer  = require('multer');
const upload = multer();

module.exports = function(app) {
	app.post('/processEmail', upload.array(), ProcessEmail.ParseEmail);	
}

Inbound Parse WebhookのPOSTリクエストはデータをマルチパートフォーム形式で送信するため、リクエストデータをオブジェクトに変換するミドルウェアを利用する必要があります。multipartyという選択肢もありましたが、今回はシンプルかつ利用しやすさを考慮してmulterというnpmパッケージを選択しました。それから、メールをパースするParseEmailという関数にリクエスト内容を渡し、メールの内容から関連するスタートアップの情報を取得してデータベースに登録するワーカにそのデータを渡します。

このアプリケーションがメールから関連するフィールドが取得できない時は、メール送信APIを利用してチームにメールの元コンテンツやフィールド変数を通知します。通知処理にはSendGridのNode.js向け公式ライブラリを利用しています。パース処理中に何らかのエラーが発生した際もこの方法で通知しています。

メールのパースに成功したら、ワーカにスタートアップに関するオブジェクト(startupMsg.data)と元メッセージ(startupInfo.originalEmail)を渡します。ワーカはPhantomJSスクリプトを利用してstartupMsg.dataをWebサイトのフォーム経由で送信します。データベース登録処理中にエラーが発生したら、startupInfo.originalEmailをチームに送信してメールの元コンテンツとともにエラーがあったことを通知します。このようにして、何があっても漏れがないようカバーしています。

var parseText = require('./parse-text');
var Email = require('./email');
var EmailJob = require('./start-email-job');
var util = require('util');

exports.ParseEmail = function(req, res) {
	var fields = req.body;	
	var startupInfo = parseText.getFields(fields);

	if (startupInfo == null) {
		console.log('Sending fail email');
		Email.failedSubmission(fields);
		res.sendStatus(200);
		return null;
	}

	var startupMsg = {
		data: startupInfo,
		originalEmail: fields
	};

	EmailJob.startJob(startupMsg, function() {
		res.sendStatus(200);
	});
}

今回の試みで、Inbound Parse Webhookを使ってタスクの自動化と合理化が簡単に行えることがわかりました。この記事をお読みの皆さんがこの機能をどうやって利用しているか興味があります。是非こちらから連絡していただくか、FacebookTwitterなどでシェアしてください。