SendGridとNode.jsを使ってFAXをメールとして転送する方法
- 2020年10月6日
- by SendGrid
- Category: 技術ネタ
この記事は Forward fax to email with SendGrid and Node.js の抄訳です。
2020年の今、FAXを受信しなくてはいけない。そんな時あなたならどうしますか?FAX機を購入して、電話回線に接続し、自分のFAX番号を相手に知らせる、みたいなことはできるでしょう。でも、今は2020年です。昔とは違う未来に生きているのですから、Node.jsといくつかのAPIを使って、FAXをメールに変えてみましょう。
ここで必要なのは、TwilioアカウントとSendGridアカウントです。あとは今回構築するFAX/メール変換アプリにより失われる、このFAXのノイズ音もお忘れずに。
FAXの受信
今回は、ゴツいFAX機ではなく、Twilioの番号を使ってFAXを受信します。変換アプリを構築するために、FAXをサポートしているTwilio番号が必要になります。Twilioアカウントにログインして、新規で購入するか既に持っている番号を利用してください。以下のアイコンがFAXをサポートしていることを意味しています。
番号の準備ができたら、Webhookを受信するための設定を行います。FAXはSMSと似たような動きをすると思われるかもしれませんが、実は音声通話に近いものです。実装するためには2種類のWebhookを受信する必要があります。1つ目のWebhookで、FAXの受信もしくは拒否の選択をすることができます。具体的には、TwilML内のverbで、<Receive>(受信)もしくは<Reject>(拒否)を利用します。
着信したFAXを拒否すると接続は切断されます。一方、受信を選択すると、Twilioが電話に出て、あなたの代わりにFAXを受信します。これを行うには、<Receive>タグのaction属性に2つ目のWebhookのURLを設定します。
2つ目のWebhookは、FAXをPDFとしてダウンロードするためのもので、これをメールとして送信します。今回は、2つ目のWebhookの受信環境を、Node.jsを使ってTwilio Function上に構築します(任意の言語で実装し、ご自身でアプリケーションをホストすることももちろん可能です)。
FAXのダウンロード
別の記事でチームメイトのSamがMMSメッセージのメディアで行っていたように、FAXのPDFファイルをダウンロードしたり、SendGridのAPIを呼び出したりするのに、requestというnpmモジュールを利用します。TwilioコンソールでRuntime dependenciesセクションを開き、requestのバージョン2.88.0を追加します。
次に、SendGridアカウント上でAPIキーを作成(メール送信のためのパーミッションが必要です)して、SENDGRID_API_KEYという環境変数として保存します。
Functionを構築する前に、設定があと2つ必要です。それは、受信したFAXを送信する宛先アドレスと、メールの送信元アドレスです。それぞれ、TO_EMAIL_ADDRESSとFROM_EMAIL_ADDRESSという環境変数として保存してください。
次のパートに移る前に、設定を保存してください。
Functionのコーディング
新しいFunctionを作成し、Blankテンプレートを選択します。requestをrequireして、ハンドラ関数を作成するところからコーディングを開始します。
const request = require('request'); exports.handler = function(context, event, callback) { }
Webhookのリクエストは、FAXで受信したPDFファイルの場所を示すURLを送信してきます。そのURLは、MediaUrlパラメータに格納されています。
requestを利用してPDFファイルをダウンロードします。それをSendGridのAPIで送信するために、Bufferオブジェクトとして扱い、エンコーディングをnullに設定します。
Functionに以下の内容を追加します:
exports.handler = function(context, event, callback) { const faxUrl = event.MediaUrl; request.get({ uri: faxUrl, encoding: null }, (error, response, body) => { // body is the PDF file as a Buffer object }); }
続いて、SendGrid APIのリクエストを構築します。以前、SMSをメールとして転送する関数を作った時に使った方法と似ています。コールバック内に以下のコードを追加します:
request.get({ uri: faxUrl, encoding: null }, (error, response, body) => { const email = { personalizations: [{ to: [{ email: context.TO_EMAIL_ADDRESS }] }], from: { email: context.FROM_EMAIL_ADDRESS }, subject: `New fax from ${event.From}`, content: [ { type: 'text/plain', value: 'Your fax is attached.' } ], attachments: [] }; // more to come }
先ほど設定した環境変数から、toとfromにメールアドレスを設定します。件名には新しいFAXがあることが分かる内容を、メール本文にはFAXで受信した内容が添付されていることがわかるシンプルなメッセージを入れています。最後に、添付ファイル配列に受信したPDFファイルを追加します。
FAXのダウンロードに成功した場合、その内容をメールに添付ファイルとして追加します。そのためには、3つのパラメータを持つオブジェクトを作成します。
- content: ダウンロードしたPDFファイルのBufferをbase64エンコードした文字列
- filename: FAXのSID識別子から生成した文字列
- type: ファイルのMIMEタイプ。FAXをダウンロードした際のヘッダに含まれるものをそのまま設定
request.get({ uri: faxUrl, encoding: null }, (error, response, body) => { const email = { ... }; if (!error && response.statusCode === 200) { email.attachments.push({ content: body.toString('base64'), filename: `${event.FaxSid}.pdf`, type: response.headers['content-type'] }); } // more to come }
FAXのダウンロードでエラーが発生した場合は、添付ファイルの追加をスキップして、通知メールを送信しています。
メールが構築できたので、SendGrid APIを呼び出して送信します。先ほど作成したメールをemailオブジェクトとしてパッケージングしたら、冒頭で作成したAPIキーを認証情報として加えて送信します。
APIがステータスコード202を返して成功したら、空のTwiML<Response>を送信して、Twilioに問題がなかったことを知らせます。エラーが発生した場合は、コールバックの第一引数にerrorまたはbodyを渡し、Functionがエラーになったことをログに記録するようにします。
request.get({ uri: faxUrl, encoding: null }, (error, response, body) => { const email = { ... }; if (!error && response.statusCode == 200) { // add attachment } request.post( { uri: 'https://api.sendgrid.com/v3/mail/send', body: email, auth: { bearer: context.SENDGRID_API_KEY }, json: true }, (error, response, body) => { if (error) { return callback(error); } else { if (response.statusCode === 202) { return callback(null, new Twilio.twiml.VoiceResponse()); } else { return callback(body); } } } ); }
FAXを転送する処理はこれで全てです。コードの全体は以下のとおりです:
const request = require('request'); exports.handler = function(context, event, callback) { const faxUrl = event.MediaUrl; request.get({ uri: faxUrl, encoding: null }, (error, response, body) => { const email = { personalizations: [{ to: [{ email: context.TO_EMAIL_ADDRESS }] }], from: { email: context.FROM_EMAIL_ADDRESS }, subject: `New fax from ${event.From}`, content: [ { type: 'text/plain', value: 'Your fax is attached.' } ], attachments: [] }; if (!error && response.statusCode === 200) { email.attachments.push({ content: body.toString('base64'), filename: `${event.FaxSid}.pdf`, type: response.headers['content-type'] }); } request.post( { uri: 'https://api.sendgrid.com/v3/mail/send', body: email, auth: { bearer: context.SENDGRID_API_KEY }, json: true }, (error, response, body) => { if (error) { return callback(error); } else { if (response.statusCode === 202) { return callback(null, new Twilio.twiml.VoiceResponse()); } else { return callback(body); } } } ); }); }
Functionにパス(path)を設定して保存します。
仕上げ
用意したFAX番号の編集画面に戻って、「Voice & Fax」セクションでFAXの着信を受け入れるように設定されていることを確認してください。
「A fax comes in」でTwiMLを選択し、赤いボタンをクリックして新しいTwiML Binを作成し、FAXを受信できるようにします。以下のTwiMLを入力して、action URLを上で作成したFunctionのURLに置き換えます。
<?xml version="1.0" encoding="UTF-8"?> <Response> <Receive action="FUNCTION_URL" /> </Response>
番号の設定を保存したら、FAXを受信する準備が整いました。
まとめ
今の時代、送信テストをしようにもFAX機を持っていません。近所の図書館やプリントショップで借りるか、TwilioのAPIエクスプローラを利用してAPI経由でFAXを送りましょう(ここでは、ToとFromとして既存のFAX番号を利用できます)。FAXを送信する際は、PDFファイルをTwilioからアクセスできる場所に保存しておく必要があります。保存場所がない場合は、こちらのテスト用PDFファイルを利用してください。
送信する際は、ちゃんとFAXの音を流すことを忘れないでください。
数分待って(FAXは時間がかかるのです!)、メールが届くことを確認します。
新しいFAXが届いているはずです。
おめでとうございます!
本記事の執筆にあたり、FAX機に被害はありませんでした
Twilio番号、JavaScript、Twilio Function、TwiML Bin,そしてSendGrid APIの力でメールボックスで直接FAXを受信できるようになりました。
requestを使ってファイルをダウンロードし、SendGrid APIに直接投稿する方法を見てきました。同じテクニックを使って、受信したMMSメッセージをメールに転送することもできます。
JavaScriptとメールでFAX問題を解決できるなんて想像したことはあるでしょうか?他にもクラシックな技術を今どきのやり方で置き換えることができるかもしれません。何かいいアイデアがあったらぜひTwitterでお知らせください!2020年版FAX万歳!
ヘッダーのFAXアイコンはEmojioneバージョン2の提供です。