4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

twilioからvonageに移行してみた

Last updated at Posted at 2023-02-22

公開されてはいけないものがコード内にあったので、再投稿
English version is here.

Motivation

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

Vonageのアカウントを取る

vonage japan?のサイトの右上のログイン
vonagelogin1.png
コミュニケーションAPIログイン
vonagelogin2.png
Sign upからfree accountを作れます。10ユーロ分のクレジットが付与され、諸制限ありますが、私の目的において使えるかどうか試すには事足りました。
張り付けている画像のWebブラウザはMacのsafariなのですが、途中から登録ボタンとかを押しても先に進まなくなったので、諦めてWebブラウザをIronに変えたら動きました。
vonagelogin3.png

API使ってSMSを飛ばす

Developer SiteのSend an SMSサンプルコードを参考に、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

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

IMG_50D17B8DA058-1.jpeg

twilioからのマイグレ

twilioとSendGridとherokuでキャリアメール代替プッシュ通知のコードを下記のように修正しました。
heroku上のweb serviceをrenderに移行してみたで、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
brand and campaign云々はA2P 10 DLC - The 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 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

Applicationsにも反映されます。
Screen Shot 2022-12-08 at 17.36.19.png

順番忘れましたが、買った電話番号に紐づける必要があります。元々Linkとなっていた赤囲みのボタンを押すと紐づけられるようです。
Screen Shot 2022-12-09 at 20.58.16.png

コード

上のコードを改変してますが、主な所だけ抜粋します。Voice API > 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でキャリアメール代替プッシュ通知のコードからだと、大まかには下記な修正になっています。コメントアウトや途中で細かい修正を経由してたりはありますが

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に移行してみたの通りrender.com上にアプリがあるので、EnvironmentからVONAGE_APPLICATION_IDとして上記IDを環境変数に設定し、Secret Filesにprivate.keyの中身を貼り付けました。貼り付けたファイルは/etc/secrets配下に配置されるそうです。
Screen Shot 2022-12-08 at 17.50.45.png

最後に

日本の電話番号に送る限りは電話番号を取る必要がないので、twilioのように法人や個人事業主じゃないとアカウントすら取らせないよと言い出さなければ。。。
ちなみにVonageはEricssonの子会社になってます。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?