TwilioでFAXを送信してみた

こんにちは。
[OPENLOGI Advent Calendar 2017](https://qiita.com/advent-calendar/2017/openlogi) 22日目担当の@tsuemuraです。
[株式会社オープンロジ](https://www.openlogi.com/corp/index.html)で、同名のサービス [OPENLOGI](https://www.openlogi.com/) の開発に携わっています。

皆さん、FAX使ってますか？[固定電話を使ったことがない新卒](https://togetter.com/li/961575)なんて逸話が出始めるほど世の中が進歩していますから、FAXを使ったことがない人も今後増えてくるのでしょう。時代の流れですね。
ですが、ご存知のようにFAXが現役バリバリで稼働しているということはビジネスにおいてはさほど珍しくなく、僕たちオープンロジのフィールドである物流業界においても例外ではありません。業務フローにしっかり組み込まれてしまっていて、変えようにも変えられないという会社は多いのではないかなと思います。
紙ベースでのやり取りはITリテラシに左右されずわかりやすい利点がある反面、どうしても自動化が難しく、コスト増の要因になりがちですね。

ところで、REST APIで電話をかけられることでおなじみ、TwilioでFAXが送信出来るのをご存知でしょうか？(記事執筆時点ではまだDevelopers Preview)
公式の[クイックスタート](https://jp.twilio.com/docs/api/fax/quickstart#allow-twilio-to-talk-to-your-web-application)に沿って試してみました。

## 環境
- Python 3.6.3

## 準備

- Twilioのアカウントを取得
- Twilio上で電話番号の取得
- 必要なライブラリのインストール
    - `sudo pip install flask twilio`

## コールバックを受け取るためのWebhookを作成する

Twilioは以下の2つのタイミングで、予め指定したURLに対してリクエストを送信します。

- 送信ステータスが変更されたタイミング
- FAXを受信したタイミング

これらを受け取れるよう、事前にWebhookを用意しておきましょう。
以下は公式のクイックスタートに記載された`Flask`用スニペットを、単体動作するよう若干変更したものです。`python main.py`とすることで実行することができます。

```main.py
#!/usr/bin/env python

from flask import Flask, Response, request

app = Flask(__name__)

@app.route('/fax/sent', methods=['POST'])
def fax_sent():
    twiml = """
        <Response>
            <Receive action="/fax/received"/>
        </Response>
    """
    print(request.stream.read())
    return Response(twiml, mimetype='text/xml')

@app.route('/fax/received', methods=['POST'])
def fax_received():
    print(request.stream.read())
    return '', 200

if __name__ == "__main__":
    app.run('0.0.0.0', 8080)
```

準備が出来たら、Twilio上で電話番号の設定の所に、コールバック先のURLを入力してください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/112393/9732687c-ae38-e724-1959-c08da71da1be.png)

なお、上記のスクリプトをローカルで動かす場合はTwilioがアクセス可能なURLが存在しないので、Web上のサーバで動かすか、[ngrok](https://ngrok.com/download)などを用いてパブリックアクセス可能なURLを用意してください。

## 送信用のPDFファイルを用意する

Twilioでは送付するFAX文面はPDFのみ対応しているようです。また、Twilioがアクセス可能なようにWeb上に配置されていないといけません。手頃なストレージにアップしておきましょう。
ちなみに、試していませんが、BASIC認証に対応しているようです。

## 送信する
ちょっと試してみるくらいのときには[API Explorer](https://jp.twilio.com/console/runtime/api-explorer/fax/fax/create)が便利です。ブラウザ上からリクエストを送ったり、サンプルコードを生成(Developers PreviewではCurlだけのようです)したりすることができます。
送信用のエンドポイントは `POST /faxes` ですので、こちらに必要事項を入力して `Make Request` で実行します(課金が発生する場合はこのタイミングで発生するので気をつけてください)。

最低限必要な項目は

- TO
- Media URL
- FROM

です。`TO`には送信先のFAX番号、`FROM`には送信元のFAX番号、　`MEDIA URL`には送信するPDFファイルのURLを記載します。

また、`STATUS CALLBACK`にWebhookのURLを指定しておくと、送信結果が通知されます。

送信に成功すると、こんな感じのレスポンスが返ってきます。

```
{
    "media_sid": null,
    "status": "queued",
    "direction": "outbound",
    "from": "+81xxxxxxxx",
    "date_updated": "2017-12-21T20:08:39Z",
    "price": null,
    "account_sid": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "to": "+13658000154",
    "date_created": "2017-12-21T20:08:39Z",
    "url": "https://fax.twilio.com/v1/Faxes/FXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "sid": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "duration": null,
    "num_pages": null,
    "quality": "fine",
    "price_unit": null,
    "api_version": "v1",
    "media_url": null,
    "links": {
        "media": "https://fax.twilio.com/v1/Faxes/FXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/Media"
    }
}
```

`STATUS CALLBACK` にWebhookのレスポンスを指定しておくと、ステータスが`delivered`に変更されたタイミングで通知が届きます。

```
FaxSid=xxxxxxxxxxxxxxxxxxxxxx
&ApiVersion=v1
&MediaUrl=https%3A%2F%2Fmedia.twiliocdn.com%2Ffax%2xxxxxxxxxxxxxxxxxxxxxxxxxx
&NumPages=1
&OriginalMediaUrl=http%3A%2F%2Fxxxxxxxxxxxxxxxxxx.pdf
&FaxStatus=delivered
&To=%2B8100000000000
&From=%2B810000000000
&AccountSid=xxxxxxxxxxxxxxxxxxxxxxxxx
&RemoteStationId=000000000000000
```

## 他サービスと比べて
Twilio以外にもFAX送受信のサービスは国内外問わず存在しますが、送受信がメールでのやり取りだったり、送信結果を問い合わせるのに別のAPIを叩く必要があるなど、微妙に使いづらさがあります。

TwilioはREST APIでのやりとりが出来、送信結果の確認をコールバックで受け取れるなど、他サービスと比べてプログラマブルというか、Webサービスに組み込みやすい感じがあります。

今回、受信側はeFaxを使ったのですが、送信から受信まで3分くらい掛かりました。どこにボトルネックがあるのかわからないのですが、この辺は正式リリース時にはもうすこし早くなってるといいですね。