Twilio + Google Apps Scriptで着信拒否つき留守電サービスを作る
格安SIMにしちゃうと留守電代金も惜しくなる
docomoからiijに移行してから、もうすぐ2年ぐらいにはなるのですけど、そういえば留守電的なのを契約してなかったんですよね。
一応プランとしては存在するのだけど、月額300円はちょっと課金するにも惜しいなと。
料金・仕様 | タイプD | IIJmio
まぁ、無いときは作ることにします。
今回は、業務でガチャガチャいじったこともあり、TwilioとGoogle Apps Scriptで実装することにしましょう。
Twilioとは?
最近はやりのクラウドですね。クラウド電話APIといいまして、クラウド経由でWebサービスと電話を連携すれば便利じゃね?
みたいなサービスです。国内だとKDDIさんが提供しています。基本的には従量課金。
詳細は本家のWebでも見て下さい。
Twilio for KDDI Web Communications | クラウド電話API
Google Appsとは?
Google版VBAみたいなもんです。
Google 様のアナルを舐めれば幸せになれる の各種サービスを便利に使える言語 でして、サーバー側でJavascript的なものが動いているという認識で大丈夫かと思います。
Googleサービスだと、GmailだのカレンダーだのDriveだのいろいろとあるわけですが、そこら辺を使ってゴチャゴチャできるわけです。
詳細は下記あたりで。
Apps Script | Google Developers
まずはTwilio側の準備
Twilioアカウントを作る
Twilioのサイトにアクセスし、右上の[サインアップ]から登録します。
途中でSMS認証を求められるので、携帯電話番号を一つ用意しないといけません。
Twilio for KDDI Web Communications | クラウド電話API
認証を終了するとチュートリアルが云々と出ますので、見るといいかと思います。
GetStartedで飛ばしてもいいですけど。
Twilioのダッシュボードはこんな感じです。
電話番号を取得する
今回の留守電は、自分のケータイに着信した電話を、時間をトリガーにしてTwilio側に転送する形になります。
取りあえず一つ、電話番号を取得します。
コンソールダッシュボードの[プログラマブルVoice]をクリック。
電話番号ダッシュボードが表示されます。 赤色の[始めましょう]をクリック。
初期状態だと番号が払い出されていないですので、 [最初のTwilio電話番号を取得]をクリック。
いきなり番号を提示されます。表示された番号が気にくわないなら、「別の番号を検索する」リンクをクリックすれば、選択画面に移行します。
取得できる番号が羅列されます。どれでもいいんじゃね、とは思いますが、特定の番号が含まれる電話番号なども検索可能です。
無事に取得できました。
続いてGoogleDrive側の下準備
Web版のGoogleDriveが使える状態を前提に進めます。
‘Twilio'フォルダと'Record'フォルダを作る
正直フォルダ階層の概念はGoogleAppsScriptには存在しないのですが、人間様がわかりづらいですので、ルートの直下に「Twilio」とでもフォルダを作りましょう。今回はそこにいろいろとファイルを置いていきます。
作成したフォルダの直下に「Record」というフォルダも作りましょう。そこに録音データを保存していきます。
Apps Scriptの準備
まずはApps Scriptを使えるようにします。
Web版GoogleDriveの[新規]→[その他]→[アプリを追加]とクリック。
ドライブにアプリを追加、というウィンドウが表示されますので、検索欄に'script'と入力。
Google Apps Scriptがサジェストされますので、[接続]をクリック。
ドライブに接続されました、というウィンドウが表示されれば問題なしです。次へ進みます。
記録用に使うスプレッドシートを作る
今回はログをGoogleスプレッドシートに記録していきます。Excelみたいなやつですね。
スクショは忘れましたが、マイドライブの[新規]→[Googleスプレッドシート]とクリックすれば作成できます。
新規作成できたら、シート名を「twilio」に設定し、「log」というシートと「blocking」というシートの2つ作ります。
「log」が電話ログを記録するシート、「blocking」が拒否する電話番号を記載するシートです。
もしかしたら「blocking」シート側に何もはいってないとエラー出ちゃうかもしれませんので、
何か適当に拒否したい人間の番号を1列目に入れておいてください。
親とか実家とか
スクリプトファイルを作る
今回は、一番最初に電話を受けるスクリプト、留守電を録音するスクリプト、の2つファイルを作ります。
マイドライブの[新規]→[その他]→[Google Apps Script]とクリック。
エディタが開きますので、'twilio'とでも名付けましょう。
作成直後は'myFunction'みたいなやつが出てきますが、不要です。
同じ事を繰り返して、もう一つは'twilio_record'にでもしましょう。
Moment.js を使えるようにする
日付云々でラクなライブラリ、Moment.jsを使えるようにしましょう。
各々のスクリプトファイルで必要になりますので、このタイミングで使えるようにしましょう。
メニューバーの[リソース]→[ライブラリ]とクリック。
「含まれているライブラリ」ウィンドウが表示されますので、
[ライブラリを検索]テキストボックスに下記のプロジェクトキーを入力し、[選択]をクリックします。
バージョンのプルダウンから最新版を選び、[保存]で確定させてください。
MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48
よくよく考えれば、今回のスクリプトには必須ではないので、そこら辺は適時でお願いします。
構成の確認
こんな感じですかね。
必要になるもののメモ
Twilioの ‘ACCOUNT SID'と'AUTH TOKEN’
Twilioのコンソールダッシュボードに書いてありますので、コピーしておきましょう。
‘Record'フォルダの'FolderID’
録音データの保存先として作成した'Record'フォルダのIDです。 GoogleDriveで'Record'フォルダを開き、アドレスバーに書いてある英数字の羅列をコピーしておきましょう。
‘twilio'スプレッドシートのID
フォルダと同じく、先ほど作成したスプレッドシートのIDもコピーします。 フォルダIDと同じく、アドレスバーに書いてある英数字をコピー。
コードをガリガリ書いていく
あとはひたすらコードを書いていきます。 詳細の解説は気が向いたら書くことにします。
‘twilio_record'スクリプト
まずは録音側。
//Twilio var twilioSid='{ twilio の ACCOUNT SID }'; var twilioAuth='{ twilio の AUTH_TOKEN }'; function doGet() { return; } function doPost(e){ var fileName = Moment.moment().format('YYYY/MM/DD-hhmmss'); var recordUrl = e.parameter['RecordingUrl']; var caller=e.parameter['Caller']; caller=caller.replace('+81','0'); var result = UrlFetchApp.fetch(recordUrl); var fileBlob = result.getBlob(); fileBlob.setName(fileName); //GoogleDriveに録音データを保存 var outputDir = DriveApp.getFolderById('{ GoogleDriveのDriveID }'); var recordDetails = outputDir.createFile(fileBlob); var sharingUrl = recordDetails.getUrl(); //Twilioサーバーの録音データを消去 delRecord(recordUrl); //メールを送信 sendMail(caller,Moment.moment().format('YYYY/MM/DD hh:mm'),sharingUrl); var out = ContentService.createTextOutput(buildXml()); out.setMimeType(ContentService.MimeType.XML); return out; } function buildXml(){ var outString = ''; outString +='<?xml version="1.0" encoding="UTF-8"?>'; outString += '<Response>'; outString += '<Say language="ja-jp" voice="woman">'; outString +='メッセージをお預かりいたしました。 '; outString +='お電話ありがとうございました。'; outString += '</Say>'; outString += '<Hangup />'; outString += '</Response>'; return outString; } function delRecord(urlData){ urlData+=".json"; var options = { method: "delete", headers: { Authorization: " Basic " + Utilities.base64Encode(twilioSid + ":" + twilioAuth) },muteHttpExceptions: true }; var result = UrlFetchApp.fetch(urlData,options); } function sendMail(callerString,dateString,urlString){ var mailTo='{ 通知メールを飛ばすメールアドレス }'; var mailSubject='留守電通知'; var mailBody=''; mailBody += '留守電がありました\n'; mailBody += '日時 : ' + dateString + '\n'; mailBody += '相手先 : ' + callerString + '\n'; mailBody += '録音データ : ' + urlString + '\n'; MailApp.sendEmail(mailTo,mailSubject,mailBody); }
最後のおまじない
編集が終わったら、メニューバーの[公開]→[ウェブアプリケーションとして導入]をクリック。
現在のウェブアプリケーションのURLに書いてあるURLをコピーしましょう。次のスクリプトファイルで使います。
アプリケーションにアクセスできるユーザーは、「全員(匿名ユーザーを含む)」にしないとうまくいきません。
承認を求められるので[許可を確認]をクリック。
なぜだか一旦無効にしないとうまくいかない、GoogleAppsScriptの謎。
ということで、再度メニューバーから[公開]→[ウェブアプリケーションとして導入]をクリック。
開いたら[ウェブアプリケーションを無効にする]をクリックし、[はい]で決定。
再びメニューバーから[公開]→[ウェブアプリケーションとして導入]をクリックし、公開し直します。
よくわかんないですが、おまじないみたいなもの なので忘れないように。
‘twilio'スクリプト
var Sheets=SpreadsheetApp.openById('{ スプレッドシートのID }'); var logSheet=Sheets.getSheetByName('log'); var blockSheet=Sheets.getSheetByName('blocking'); function doGet(e){ return; } function doPost(e){ return receive_(e); } function receive_(e){ //発信者情報を取得 var caller=String(e.parameter['Caller']); caller=caller.replace('+81','0'); //BlockingListの判定 var blockArr=blockSheet.getRange(1,1,blockSheet.getLastRow(),1).getValues(); var blockRes=blockArr[0].filter(function(element,index){ if(String(element) ==String(caller)){ return true; } }); var out; var setRow=logSheet.getLastRow()+1; if(blockRes.length==0){ //Block判定ではない logSheet.getRange(setRow,1).setValue(Moment.moment().format('YYYY/MM/DD hh:mm')); logSheet.getRange(setRow,2).setValue(caller); logSheet.getRange(setRow,3).setValue('record'); var result=buildXml(); out = ContentService.createTextOutput(result); }else{ //Block判定 logSheet.getRange(setRow,1).setValue(Moment.moment().format('YYYY/MM/DD hh:mm')); logSheet.getRange(setRow,2).setValue(caller); logSheet.getRange(setRow,3).setValue('blocked'); var result=buildXmlBlock(); out = ContentService.createTextOutput(result); } out.setMimeType(ContentService.MimeType.XML); return out; } function buildXml(){ var outString = ''; outString +='<?xml version="1.0" encoding="UTF-8"?>'; outString += '<Response>'; outString += '<Say language="ja-jp" voice="woman">'; outString += 'ただいま、電話に出ることができません。 '; outString += 'メッセージを録音します。 '; outString += '「ピー」という音の後に、60秒以内で、お名前、お電話番号、ご用件を録音し、'; outString += '最後にシャープを押してください。'; outString += '</Say>'; outString += '<Record action="{ twilio_recordスクリプトのウェブ公開URL }" finishOnKey="#" maxLength="60" method="post" timeout="75" />'; outString += '</Response>'; return outString; } function buildXmlBlock(){ var outString = ''; outString +='<?xml version="1.0" encoding="UTF-8"?>'; outString += '<Response>'; outString += '<Reject />'; outString += '</Response>'; return outString; }
こちらも最後のおまじない
編集が終わったら、メニューバーの[公開]→[ウェブアプリケーションとして導入]をクリック。
現在のウェブアプリケーションのURLに書いてあるURLをコピーしましょう。Twilioのページで使います。
アプリケーションにアクセスできるユーザーは、「全員(匿名ユーザーを含む)」にしないとうまくいきません。
承認を求められるので[許可を確認]をクリック。
なぜだか一旦無効にしないとうまくいかない、GoogleAppsScriptの謎。
ということで、再度メニューバーから[公開]→[ウェブアプリケーションとして導入]をクリック。
開いたら[ウェブアプリケーションを無効にする]をクリックし、[はい]で決定。
再びメニューバーから[公開]→[ウェブアプリケーションとして導入]をクリックし、公開し直します。
よくわかんないですが、おまじないみたいなもの なので忘れないように。
スクリプトのURLをTwilioに反映
Twilioのコンソールダッシュボードから電話番号ページに飛び、先ほど取得した番号を選択します。
‘twilio'スクリプトのウェブアプリケーションURLを、[A CALL COMES IN]項目のURL欄に貼りつけます。
POSTかGETを選べますが、POSTにしといてください。[保存]を押して終了。
動作確認
試しに、先ほど作った番号に電話してみましょう。
メール通知が来ます
留守電の記録&ブロックが発生すると、メールで通知が来るようにしました。
GoogleDriveへのリンクも貼ってあります。
GoogleDriveに録音データがアップされます
録音ファイルはこちらに。
スプレッドシートには
記録されてますね。ブロックされたものは'blocked'表記になります。
誰でも簡単に
こういうものが作れる時代って便利ですね。実際にコード書いてた時間なんでせいぜい30分ですし。
コードを書いている時間が30分に対して、この記事を書いた時間が1時間以上かかってるんですけどね!!