SendGrid・Twilio・AWS Lambdaを使ってメールからSMSへメッセージを送ってみた

SendGrid・Twilio・AWS Lambdaを使ってメールからSMSへメッセージを送ってみた

新人の青木です!

今回は、Twilioのブログ「Build a Serverless Email to SMS Gateway with Twilio and AWS Lambda」で取り上げられている、SendGridとTwilio、AWS Lambda(以後Lambda) を使ったメールからSMSへの転送機能の構築について紹介します。
SendGrid, Twilio, AWSを勉強するという意味も込めて上記ブログ記事の内容を実装してみました。それぞれの機能を実際に手を動かしながら学べるので、皆さんも試してみてください!

メールをSMSに転送する流れ

ある特定のドメインに対してメールを送ると、そのメールの内容がSMSとなって指定の電話番号に届きます。
流れは以下の通りです。

メールをSMSに転送する流れ

  1. <SMSを届けたい電話番号>@<自分で管理しているドメイン>宛にメールを送信(例:+81XXXXXXXXXX@example.com)
  2. SendGridでメールを受け取り、Lambda上のアプリケーションにデータをPOST
  3. Lambda上でSMSメッセージを作成し、TwilioのAPIでスマホへ転送

手順

必要なもの

私が動作確認した環境は、macOS Catalina (10.15.7)・Google Chrome (87.0.4280.67)です。GitとnpmはHomebrewでインストールしました。

Step 1: Twilioアカウント情報の確認

Twilioアカウントをまだ持っていない方は、先にアカウントを作成しておきましょう。
機能制限はありますが、無料のトライアルアカウントも利用できます。

以下のアカウント情報を後で使います:

  • Account SID: Twilioのダッシュボードに記載
  • Auth Token: 同じくTwilioのダッシュボードに記載
  • Twilio Phone Number: SMSメッセージの送信元となる電話番号

Twilioアカウント情報の確認

Step 2: サンプルコードのダウンロード

引用元のブログ記事によると、

Lambdaにnpmパッケージを直接インストールすることはできない、とのことなので、今回はサンプルコードを一度ダウンロードし、ローカル環境でパッケージ化した上でAWSへアップロードする必要があります。

手順は以下の通りです:

  1. GitHubからリポジトリをダウンロードもしくはcloneする
    % git clone https://github.com/bdm1981/emailtosms-gateway.git
  2. cdでディレクトリ内に移動し、npm installを実行する
  3. ディレクトリ内のファイル・フォルダをZIPする

ここでひとつ注意点があります。
パッケージ化の際は、ディレクトリの中身を選択してZIPにするようにしましょう(ここではArchive.zipとします)。

パッケージ化はZIP

これは私自身が犯したミスですが、
/emailtosms-gatewayをディレクトリごとZIPにしてLambda上にアップロードすると、アプリ実行時に次のエラーが発生し上手く動作しません:

Runtime.HandlerNotFound: index.handler is undefined or not exported

これは、ZIP圧縮の際に不要なディレクトリが入ってしまい、アプリがパスを解決できなくなったことが原因で出たエラーです。(参照:stackoverflow – AWS Lambda function returning Runtime.HandlerNotFound error

次のステップで、zipファイル(Archive.zip)をLambdaへアップロードします!

ですがその前に、今回実行するindex.jsの中身が気になる方のために、コードの一部を載せておきます:

exports.handler = async (event) => {
  let data = await parser.parse(event);

  console.log("input data: ", data);

  if (validateSender(data.from)) {
    // parse the to number from the left-hand side of the email address

    let regexp = /(^.\d+[^@])/g;

    let to = data.to.match(regexp)[0];

    let body = `Subject: ${data.subject}\nMessage: ${data.text}`;

    let message = await client.messages.create({
      body: body,

      from: process.env.FROM,

      to: to,
    });

    console.log("Message Output: ", message);

    const response = {
      statusCode: 200,

      body: JSON.stringify({ input: data, output: message }),
    };

    return response;
  } else {
    const response = {
      statusCode: 403,

      body: "Unauthorized Sender",
    };

    return response;
  }
};

おおまかなコードの流れは以下の通りです:

  • SendGridから送られるペイロードから、fromtobodysubjectを取り出す
  • fromアドレスを、Lambdaの環境変数設定で許可した送信ドメインのリストと照合する(次のステップで説明)
  • toアドレスから電話番号を抽出する
  • Twilio helper libraryを用いてSMSメッセージを作成する
    (TwilioのAPIを用いたSMSメッセージ作成の詳細については、「Programmable SMS Quickstart for Node.js」に記載)

これでメールからSMSへ転送する機能の準備ができたので、AWSでの環境構築に移っていきます!

Step 3: Lambda関数とAPI Gatewayの構築

前のステップで、メールからSMSへ転送するコードの準備ができました。
ここでは、AWS Lambdaへzipファイルをアップロードし、Amazon API Gatewayを使ってデータ転送のためのルートを確保していきます。

Lambda関数の新規作成

AWS Management Console

  1. まずは、AWSのコンソール画面のFind Servicesから”lambda”と検索してLambdaのコンソール画面へ移動する
  2. Create Functionをクリック
  3. Author from scratchを選択し、関数名を設定 (今回はemailToSMS)、RuntimeはNode.js 12.xとする
  4. Create Functionをクリック
zipファイルのアップロード

関数を作成できたので、今度は先ほど準備したコードを追加します。

Upload a .zip fileを選択します。

Upload a .zip fileを選択

先ほど作成したzipファイル(Archive.zip)を選択しアップロードします。

環境変数の設定

今回使用するコード内では、Twilioアカウントの重要な情報を変数として定義しています。
以下の画面で、アカウント情報を環境変数として設定します。

環境変数の設定

ここでは、次の4つの環境変数を設定します:

  1. ACCOUNT_SID: Step 1で確認したアカウント情報
  2. AUTH_TOKEN: Step 1で確認したアカウント情報
  3. FROM: Step 1で確認した電話番号
  4. DOMAINS: このゲートウェイへのメールの送信元ドメインを指定する (複数ある場合はコンマで区切る)

なお、DOMAINSで指定していないドメインから送信した場合、ドメイン認証が通らず、SMSメッセージが生成されない、といった仕組みになっています。

API Gatewayの設定

コードの設定が完了しました。
次に、Lambda関数を呼び出すために必要となる、API Gatewayを設定します。

画面のDesignerで、Add triggerを選択します。

Add triggerを選択

API Gatewayを選択し、APIには今回作成したemailToSMS-APIを、
Deployment stageにdefault、SecurityにOpenを選択します。

Add trigger

AddをクリックするとAPI Gatewayが追加されます。
以下の画面に表示されるAPIエンドポイントのURLをコピーしておきます。

API Gateway

最後に、上の画面中のemailToSMS-APIをクリックしてAPI Gatewayのコンソール画面に移動し、SettingsのBinary Media Typesmultipart/form-dataが追加されていることを確認しておきましょう。

Settings

Binary Media Types

これで、アップロードしたLambda関数を呼び出す新しいルートが完成しました!
次に、受信したメールのデータをこのルートにPOST送信するようにSendGridの設定を行います。

Step 4: SendGridの設定

転送機能とルートの整備ができたので、あとはメールをSendGridで受信して、この機能を呼び出す仕組みを設定するだけです!
ここで登場するのが、SendGridのInbound Parse Webhook機能です。
(SendGridアカウントをまだ持っていない方はこちらで作成しておきましょう。)

Inbound Parse Webhookは、特定のホストへのメールをSendGridが受け取り、そのメールのデータを指定されたURLへPOSTする機能です。

まずは、SendGridでメールを受けるためにドメインを準備しましょう!
ドメイン準備の手順は以下の通りです:

  1. メールを受信するドメインの取得(Freenomお名前.comなど)
  2. Domain Authenticationの設定
  3. MXレコードの設定

以上が完了したら、Inbound Parse Webhookの設定を行っていきます!
設定の詳細については、こちらのブログをご覧ください。

SendGridのコンソール画面Settings / Inbound Parseを選択します。

Settings / Inbound Parseを選択

Add Host & URLをクリックします。

Add Host & URL

Destination URLには、前のステップでコピーした、APIエンドポイントのURLを入力します。

Inbound Parse Webhookで設定したドメインに向けたメールはすべて、目的のURLへPOSTされます。

これで準備は完了です!
それでは、メールを送ってみましょう!

結果

メールからSMSへメッセージが届きました!

Email:

結果( Email)

SMS:

結果(SMS)

送信先の電話番号について

以上の手順でSMSを受け取れないという方は、toアドレスのローカルパートの電話番号を確認してみてください。

Twilioが扱えるのは、E164フォーマットに沿った電話番号のみです:

[+] [country code] [subscriber number including area code]

なので、080XXXXXXXXの電話番号に送りたい場合は、ローカルパートを+8180XXXXXXXXに直しましょう。

最後に、Twilioのトライアルアカウントをお使いの方は、送信先となる電話番号の検証設定をお忘れなく!

なぜ、Twilio Functionsを使わなかったのか?

今回は、AWSを使ってSMS転送機能を実装しましたが、本来であれば、TwilioのTwilio FunctionsというLambdaと同様のサーバレス実行環境のサービスを用いてアプリケーションの構築ができたはずです。

引用元のブログ記事によると、

とのことで、Twilio Functionsはmultipart/form-dataのようなbinary content typeには対応していないため、今回は対応済みであるAWSを使いました。

まとめ

今回は、SendGridとTwilio、Lambdaを連携させてメールをSMSとしてスマホに転送しました。
引用元のブログ記事によると、メールをSMSに転送するレガシーなシステムをスケールできるようにしたいというお客さんの要望に応えるため、今回の仕組みを構築したそうです。

私自身は、SendGridとTwilioの両方を扱った題材でAWSの勉強もしたい、というかなり欲張りな動機でこのブログ記事の内容を試しましたが、それら全てに触れることができたので、とても良い学習材料になったと思います。ぜひ、皆さんも試してみてください!

メールを成功の原動力に

開発者にもマーケターにも信頼されているメールサービスを利用して、
時間の節約、スケーラビリティ、メール配信に関する専門知識を手に入れましょう。