twilioからvonageに移行してみた

公開されてはいけないものがコード内にあったので、再投稿
English version is [here](https://github.com/kamotsuru/voicecall-via-email).

# Motivation
[twilioとSendGridとherokuでキャリアメール代替プッシュ通知](https://qiita.com/kamotsuru/items/358f0e6f3d68ba4fc322)で、twilioのProgrammable Messagingを使ってSMSを送っていたのですが、8末で個人向けにはサービス終了したので、10末を以て現アカウントは強制解約すると言う最後通告が来たので、移行先を探してVonageに移行してみました。
[こっち](https://qiita.com/kamotsuru/items/e90a9e887c4aa2ec8bba)と似たような話だな。。。

# Vonageのアカウントを取る

[vonage japan?](https://www.vonagebusiness.jp/l/)のサイトの右上のログイン
![vonagelogin1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117100/e2f1c56f-f555-7168-a338-1e571c5c2613.png)
コミュニケーションAPIログイン
![vonagelogin2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117100/3e325d6a-338d-f7ab-9c18-47da680cb3bc.png)
Sign upからfree accountを作れます。10ユーロ分のクレジットが付与され、諸制限ありますが、私の目的において使えるかどうか試すには事足りました。
張り付けている画像のWebブラウザはMacのsafariなのですが、途中から登録ボタンとかを押しても先に進まなくなったので、諦めてWebブラウザをIronに変えたら動きました。
![vonagelogin3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117100/87b804f4-fcfe-6038-4a09-2b3a60d80666.png)

# API使ってSMSを飛ばす
Developer Siteの[Send an SMS](https://developer.vonage.com/messaging/sms/code-snippets/send-an-sms)の[サンプルコード](https://github.com/vonage/vonage-python-code-snippets/blob/master/sms/send-an-sms.py#L15-L16)を参考に、pythonでSMS送ってみました。

```
import vonage

client = vonage.Client(key="your key", secret="your secret")
sms = vonage.Sms(client)

responseData = sms.send_message(
    {
        "from": "Vonage APIs",
         "to": "8180xxxxxxxx",
        "text": "A text message sent using the Nexmo SMS API",
        }
    )
if responseData["messages"][0]["status"] == "0":
    print("Message sent successfully.")
else:
    print("status = "+responseData["messages"][0]["status"])
    print("Message faild with error: "+responseData['messages'][0]['error-text'])
```
3行目のkey/secretは上で作ったアカウントで、API Settingsのタブの自分に割り当てられたAPI KeyとAPI secretを使います。
8行目のfromがVonage APIsとなってますが、日本の番号にはこれで送れますが、米国の番号へは後述するちゃんと購入した番号でないと送れないようです。カナダもダメなそうです。
![key.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117100/ebec7804-dbc1-ec94-f9d5-e17d09172612.png)

au携帯へはこんな感じで送れますが、free accountでは[FREE SMS DEMO, TEST MESSAGE]というメッセージが付きます。一番上が、上記pythonスクリプトで送ったものです。

<img width="300" alt="IMG_50D17B8DA058-1.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117100/a71bcbe2-67f9-c727-83f2-4fd30c51e03f.jpeg">

# twilioからのマイグレ
[twilioとSendGridとherokuでキャリアメール代替プッシュ通知](https://qiita.com/kamotsuru/items/358f0e6f3d68ba4fc322)のコードを下記のように修正しました。
[heroku上のweb serviceをrenderに移行してみた](https://qiita.com/kamotsuru/items/e90a9e887c4aa2ec8bba)で、herokuからrender.comに移行されてます。

```
13a14,15
> import vonage
> 
37a40,42
> vonage_client = vonage.Client(key=konf.vonage_api_key,
>                               secret=konf.vonage_api_secret)
> vonage_api = vonage.Sms(vonage_client)
129,131c134,136
<     for required in ['EMAIL_DOMAIN',
<                      'SENDGRID_USERNAME', 'SENDGRID_PASSWORD',
<                      'TWILIO_ACCOUNT_SID', 'TWILIO_AUTH_TOKEN']:
---
>     for required in ['TWILIO_ACCOUNT_SID', 'TWILIO_AUTH_TOKEN',
>                      'VONAGE_API_KEY', 'VONAGE_API_SECRET']:
> #    for required in ['TWILIO_ACCOUNT_SID', 'TWILIO_AUTH_TOKEN']:
215,217c220,225
<             'to': email_to_phone(envelope['to'][0]),
<             'from_': lookup.phone_for_email(email_from),
<             'body': lines[0]
---
> #            'to': email_to_phone(envelope['to'][0]),
> #            'from_': lookup.phone_for_email(email_from),
> #            'body': lines[0]
>             'from': lookup.phone_for_email(email_from).replace('+',''),       
>             'to': email_to_phone(envelope['to'][0]).replace('+',''),
>             'text': lines[0],
224,225c232,247
<         rv = twilio_api.messages.create(**sms)
<         return rv.sid
---
> #        rv = twilio_api.messages.create(**sms)
> #        '''
>         responseData = vonage_api.send_message({
> #            'from': 'Vonage APIs',
>             'from': lookup.phone_for_email(email_from).replace('+',''),
>             'to': email_to_phone(envelope['to'][0]).replace('+',''),
>             'text': lines[0],
>             'type': 'unicode',  
>         })
>         if responseData["messages"][0]["status"] == "0":
>             print("Vonage message sent successfully.")
>         else:
>             warn("Vonage message failed with error: "+str(responseData['messages'][0]['error-text']))
> #        '''
> #        return rv.sid
>         return responseData["messages"][0]["message-id"]
229,230c251,252
<         error_message = "Error sending message to Twilio"
<         return warn(error_message), 400
---
>         error_message = "Error sending message to Vonage"
>         return warn(error_message+str(responseData['messages'][0]['error-text'])), 400

```
twilioは電話番号の頭に+を求めますが、vonageは逆にあったらerrorになるので、雑に"+"を""に置き換えてます。。。

# 電話番号を買う
上述の通り、番号買わなくても日本の番号にはSMS送れるのですが、その場合0.07ユーロ(9.9円)/通、米国の番号から米国の番号へのSMSは0.0062ユーロ/(0.9円)通で、一通あたり十倍の差があります。私の場合、google voiceの米国の番号を持っているので、そっちに送った方が安いわけです。
ちなみに、電話番号の維持費(購入費含む)は0.9ユーロ(127円)/月なので、月15通送るとペイします。

ということで、クレジットカードを登録して有償アカウントにupgradeして、米国の番号を購入しました。
Buy Numbersタブから、FeasureにSMSを指定して好きな4桁とか入力すると候補が出てくるので、右のBuyから購入します。Buyボタンを押下後に、上部にもありますがbrand and campaignに紐付けないと使えない的なことを言われ、内容的に法人じゃないと登録できないっぽいのですがその登録だけキャンセルしても、実際に番号は買えて、google voiceの番号には今のところ送れています。
![buy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117100/5f382410-ede7-e983-cac8-f39dd3f7f1ca.png)
brand and campaign云々は[A2P 10 DLC - The Ultimate Guide](https://www.salesmessage.com/blog/a2p-10-dlc-ultimate-guide)によるとspam SMSが多いので、それを防ぐためいわゆる10桁の電番からSMSを送る企業に下記を登録させるようですね。
- Your company name
- The country you’re registered in
- The type of company you are
- Your tax or EIN number
- Your company’s website
- SMS campaign name, description, and use case
- Sample messages from your campaign 
- Contact information

google voiceで受信できなくなったら方法考えるか。。。

(2022/12/3追記)
12月になって、google voice宛のSMSがstatus unknownで送信されなくなってしまったので、サポートに問い合わせたところ10DLCが12/1から厳格に運用され始めたそうな。

>I have checked the reported logs and noticed that your messages from LVN 1xxxxxxxxxx to US numbers have been rejected on our hub with the reason "Illegal sender address for US destination", the blocking you are experiencing to U.S networks is due to industry-wide regulations. To ensure compliance, all traffic originating from non-10DLC or toll-free numbers will be blocked beginning on December 1st.
>
>As mentioned in our [article](https://api.support.vonage.com/hc/en-us/articles/204017023-US-SMS-Features-and-Restrictions?source=search) The US has very specific messaging restrictions and LVN can be used to only p2p traffic with exemption from network operators all SMS sent to the US must originate from a registered toll-free, 10 DLC, or short code that is associated with your Vonage account.


(2022/12/8追記)
google voice宛に電話かけることにしました。
元々転送していたメールの1行目の必要部分だけで4秒間 €0.00084667 = 0.14円で、SMS一通より安い。。。


#### Application ID取得
DashboardのGetting Started -> Make a Voice Callから、デフォルトのApplication name test-applicationのままCreate applicationを押すと、APPLICATION_IDとAPPLICATION_PRIVATE_KEYが生成され後者はprivate.keyとしてダウンロードできます。
![Screen Shot 2022-12-08 at 17.36.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117100/53e17f61-3802-0c89-1722-3a8c484b2a7a.png)

Applicationsにも反映されます。
![Screen Shot 2022-12-08 at 17.36.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117100/8afb8849-f842-8a5d-1bec-a102f21717e0.png)

順番忘れましたが、買った電話番号に紐づける必要があります。元々Linkとなっていた赤囲みのボタンを押すと紐づけられるようです。
![Screen Shot 2022-12-09 at 20.58.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117100/cb42b882-900f-b24c-98b9-0478678d7451.png)


#### コード
上のコードを改変してますが、主な所だけ抜粋します。[Voice API > Text to Speech](https://developer.vonage.com/voice/voice-api/guides/text-to-speech)を参考に、声変えたりしました。text渡すところで雑に'に'で文章ぶった切ったりしてます。。。


```
vonage_client = vonage.Client(key=konf.vonage_api_key,
                              secret=konf.vonage_api_secret,
                              application_id=konf.vonage_application_id,
                              private_key="/etc/secrets/VONAGE_APPLICATION_PRIVATE_KEY")

vonage_voice = vonage.Voice(vonage_client)

responseData = vonage_voice.create_call({      
	'from': {'type': 'phone', 'number': lookup.phone_for_email(email_from).replace('+','')},       
	'to': [{'type': 'phone', 'number': email_to_phone(envelope['to'][0]).replace('+','')}],                                             
        'ncco': [
            {
                "action": "talk",
                "text": lines[0].split('に')[1],
                "language": "ja-JP",
                "style": 2
            }
        ]
    })

return responseData["status"]
```

[twilioとSendGridとherokuでキャリアメール代替プッシュ通知](https://qiita.com/kamotsuru/items/358f0e6f3d68ba4fc322)のコードからだと、大まかには下記な修正になっています。コメントアウトや途中で細かい修正を経由してたりはありますが


```
35a36
> twilio_api = Client(konf.twilio_account_sid, konf.twilio_auth_token)
40,42c41
<                               secret=konf.vonage_api_secret,
<                               application_id=konf.vonage_application_id,
<                               private_key="/etc/secrets/VONAGE_APPLICATION_PRIVATE_KEY")
---
>                               secret=konf.vonage_api_secret)
44d42
< vonage_voice = vonage.Voice(vonage_client)
136c134,137
<     for required in ['VONAGE_API_KEY', 'VONAGE_API_SECRET']:        
---
>     for required in ['EMAIL_DOMAIN',
>                      'SENDGRID_USERNAME', 'SENDGRID_PASSWORD',
>                      'TWILIO_ACCOUNT_SID', 'TWILIO_AUTH_TOKEN',
>                      'VONAGE_API_KEY', 'VONAGE_API_SECRET']:
214,222d214
<         warn("request.form[charsets]: "+str(request.form['charsets']))
<         # if charset is iso-2022-jp, str is put back to bytes and decode as it
<         charsets = simplejson.loads(request.form['charsets'])
<         if charsets['text'].lower() == 'iso-2022-jp':
<             lines[0] = bytes(lines[0], 'utf-8').decode('iso-2022-jp').replace("\r\n", " ")
<             line_num = 1
<             while line_num < len(lines):
<                 lines[0] += bytes(lines[line_num], 'utf-8').decode('iso-2022-jp').replace("\r\n", " ")
<                 line_num += 1
229,231c221,223
<             'from': lookup.phone_for_email(email_from).replace('+',''),       
<             'to': email_to_phone(envelope['to'][0]).replace('+',''),
<             'text': lines[0],
---
>             'to': email_to_phone(envelope['to'][0]),
>             'from_': lookup.phone_for_email(email_from),
>             'body': lines[0]
238,248c230,235
<         responseData = vonage_voice.create_call({            
<             'from': {'type': 'phone', 'number': lookup.phone_for_email(email_from).replace('+','')},
<             'to': [{'type': 'phone', 'number': email_to_phone(envelope['to'][0]).replace('+','')}],
<             'ncco': [
<                 {
<                     "action": "talk",
<                     "text": lines[0].split('に')[1],
<                     "language": "ja-JP",
<                     "style": 2
<                 }
<             ]
---
>         rv = twilio_api.messages.create(**sms)
>         '''
>         responseData = vonage_api.send_message({
>             'from': 'Vonage APIs',
>             'to': 'xxxxxxxxxxxx',
>             'text': lines[0],
250c237,242
<         return responseData["status"]
---
>         if responseData["messages"][0]["status"] == "0":
>             print("Vonage message sent successfully.")
>         else:
>             print("Vonage message failed with error:{responseData['message'][0]['error-text']}")
>         '''
>         return rv.sid
254,255c246,247
<         error_message = "Error sending message to Vonage"
<         return warn(str(e)), 400
---
>         error_message = "Error sending message to Twilio"
>         return warn(error_message), 400
```



#### 環境変数登録@render.com
[heroku上のweb serviceをrenderに移行してみた](https://qiita.com/kamotsuru/items/e90a9e887c4aa2ec8bba)の通りrender.com上にアプリがあるので、EnvironmentからVONAGE_APPLICATION_IDとして上記IDを環境変数に設定し、Secret Filesにprivate.keyの中身を貼り付けました。貼り付けたファイルは/etc/secrets配下に配置されるそうです。
![Screen Shot 2022-12-08 at 17.50.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117100/ce5be564-3846-c2a7-5b2d-1ba00af76602.png)

# 最後に
日本の電話番号に送る限りは電話番号を取る必要がないので、twilioのように法人や個人事業主じゃないとアカウントすら取らせないよと言い出さなければ。。。
ちなみにVonageはEricssonの[子会社](https://www.ericsson.com/ja/press-releases/2022/7/ericsson-completes-acquisition-of-vonage)になってます。