twilio+ex_twilioでSMSを簡単に送信する

アプリを実装するほどではないし、メールでは利便性がちょっと・・・
というときにSMSでの通知が要件に上がることがあるかと思います。

ElixirでSMS送信の例としてクラウドコミュニケーションサービスTwilioと、TwilioAPIのラッパー実装として公開されているex_twilioを使って実装してみようと思います。

https://cloudapi.kddi-web.com/availability

https://github.com/danielberkompas/ex_twilio

Liveviewを使った開発の流れについては以前誰でも試せるチュートリアル記事をかきましたので、こちらをぜひ試してみて下さい。

https://qiita.com/tuchiro/items/050e6b86afc35a843a7c


# Twilioのトライアルアカウント登録を行う

まずはtwilio側の準備として無料クレジット付きのトライアルアカウントを取得し、SMS送信サービスのセットアップを行います。
無料トライアルは以下のURLから申し込みできます。
(アカウントの開設には２段階認証に使用する携帯電話番号が必要です。)

https://www.twilio.com/try-twilio


以下のページを参考に、SMSのテスト送信まで実施します。

https://www.twilio.com/ja/docs/usage/tutorials/how-to-use-your-free-trial-account

以下が大まかな流れとなります。

1. Twilioのトライアルアカウント登録と無料のクレジットを取得する。
1. 最初のTwilio電話番号(発信者としての電話番号)を取得する(Japanの番号ではSMSが対応していないので注意)
1. Programmable Messagingのサービスを作成する。
1. コンソールのTry SMSメニューからテスト送信を実施する。

### SMS送信に必要なID

twilio経由でSMS送信を行うには管理コンソール
Account > Keys & Credentials > Live credentialsから
Account SIDとAuth tokenの二つの認証情報を確認しておきます。


# ex_twilioを導入する

https://github.com/danielberkompas/ex_twilio

## phoenixプロジェクトを作成する

```
mix phx.new sample_ex_twilio
```

## 依存関係定義にex_twilioを追加してインストールします

```Elixir:mix.exs
 defp deps do
    [
      ～中略～
      {:ex_twilio, "~> 0.9.1"},
     ～中略～
    ]
  end
```

```shell:Console
cd sample_ex_twilio
mix deps.get
mix ecto.create
```

下記のパラメータに前項で確認したAccount SIDとAuth tokenを設定します。

TWILIO_ACCOUNT_SID 
TWILIO_AUTH_TOKEN 

```Elixir:config/config.exs
～中略～
config :ex_twilio, account_sid: "TWILIO_ACCOUNT_SID",
  auth_token:    "TWILIO_AUTH_TOKEN"
～中略～
```

本稿では単純化のためにConfigに直接認証情報を記載していますが、製品実装やサンプルとしてGitHubなどに公開する際は、認証情報は環境変数などコード外で設定するようにしてください
[ex_twilioのread.me](https://github.com/danielberkompas/ex_twilio)でも同様の内容が説明されています。

# SMS送信アプリのサンプル実装

### Liveviewのモデルを生成する

以下のコマンドでSMSの内容と、送信ステータスを表すLiveViewのモデル実装を生成します。

```shell:Console
mix phx.gen.live Messages SmsMessage sms_messages target_number:string calling_number:string message_body:string send_status:string
```

生成されたエンドポイントをrouterに定義します。
コマンド実行結果で提案される内容からメッセージの一覧をルート"/"に変更して登録しています。

```Elixir:lib/sample_ex_twilio_web/router.ex
　　live "/", SmsMessageLive.Index, :index
    live "/sms_messages/new", SmsMessageLive.Index, :new
    live "/sms_messages/:id/edit", SmsMessageLive.Index, :edit

    live "/sms_messages/:id", SmsMessageLive.Show, :show
    live "/sms_messages/:id/show/edit", SmsMessageLive.Show, :edit
```

## ex_twilioを使ったSMS送信機能の実装

phx.gen.liveコマンドで既にsms_messageモデルの照会登録変更削除については実装されていますので、それらとtwilio_exのSMS送信関数 Message.create/2 を使ってSMS送信とステータスの制御を実装します。


```Elixir:sample_ex_twilio/lib/sample_ex_twilio/messages.ex
  def send_sms_message(%SmsMessage{} = sms_message) do
    # 送信ステータスを送信中に更新
    {:ok, sms_message} = update_sms_message(sms_message, %{:send_status => "sending"})
　　# SMSメッセージを送信
    with {:ok, result} <-
           Message.create(
             to: sms_message.target_number,
             from: sms_message.calling_number,
             body: sms_message.message_body
           ) do
      # 正常終了した場合、ステータスを成功に更新
      {:ok, ms_message} = update_sms_message(sms_message, %{:send_status => "success"})
    else
      # エラーが発生した場合、ステータスをエラーに更新
      {:error, result} ->
        {:ok, ms_message} = update_sms_message(sms_message, %{:send_status => "error"})
        {:error, result}
    end
  end
```

一覧画面に送信ボタンのイベントハンドラを追加します。

```Elixir:lib/sample_ex_twilio_web/live/sms_message_live/index.ex
  ～中略～
  @impl true
  def handle_event("send_message", %{"id" => id}, socket) do
    {:ok, _} = id
    |> Messages.get_sms_message!()
    |> Messages.send_sms_message()

    {:noreply, assign(socket, :sms_messages, list_sms_messages())}
  end
  ～中略～
```

一覧画面のテンプレートに上記ハンドラを呼ぶ送信ボタンを追加します。
ついでに不要なshowとDeleteリンクを削除します。

```HTML:lib/sample_ex_twilio_web/live/sms_message_live/index.html.heex
  ～中略～
<td>
          <span><%= link "Send Message", to: "#", phx_click: "send_message", phx_value_id: sms_message.id, data: [confirm: "Are you sure?"], class: "button"%></span>
          <span><%= live_patch "Edit", to: Routes.sms_message_index_path(@socket, :edit, sms_message), class: "button"%></span>
          <!--
          <span><%= live_redirect "Show", to: Routes.sms_message_show_path(@socket, :show, sms_message) %></span>
          <span><%= link "Delete", to: "#", phx_click: "delete", phx_value_id: sms_message.id, data: [confirm: "Are you sure?"] %></span>
          -->
        </td>
  ～中略～
```

# SMS送信確認

Phoenixを起動します。

```shell-session:Console
mix phx.server
```

一覧画面にアクセスしNew Sms messageリンクをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243163/f2b1f3e7-4a9c-89b4-09d2-2a6056a9252b.png)

送信先の電話番号、送信元の電話番号(事前に取得したＳＭＳに対応したTwilio電話番号)、メッセージ本文、初期ステータス(適当にno_sendとしています。)を入力しsaveボタンをクリックします。
トライアルアカウントでは送信先は事前に認証済の電話番号に限定されている為、あて先はアカウント登録時にしていした電話番号を使用してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243163/46d7f82a-4eaa-d332-fc09-f15013dd0d64.png)

一覧にメッセージデータが登録されました。
SEND MESSAGEボタンをクリックすると実装した送信機能が実行されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243163/5ec8868e-9413-906e-1bb7-400b62f3f324.png)

ステータスが更新されsuccessになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243163/c13367af-0b8b-68a6-15fb-987819a9e0da.png)

送信先に指定した電話番号でSMSを受け取ることができました
※Snet from your Twilio trial account -の文字はトライアルアカウントでの送信時に自動で設定されます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243163/8ecb062e-1d2c-457c-fbac-1f9588564cba.png)

# まとめ

twilioとex_twilioを使って簡単な送信画面を実装することができました。
LiveViewを使うとベースとなるMVCのテンプレが簡単に生成できるので、実施したい部分を直ぐに動くアプリとして試作に持っていけるのがうれしいですね。