TwiML™ for Programmable SMS

TwiMLとは何か

TwiMLは、通話の着信やSMSの受信時にTwilioが行うべきことを指示するために使用される一連の命令文です。

Twilio電話番号にSMSの受信があった場合、Twilioはその電話番号に関連づけられたURLを見つけ、そのURLにリクエストを送信します。 それからTwilioはそのURLでTwiML命令を読み込み、何を行うべきか決定します。 たとえばメッセージを返信したり、メッセージのレスポンスの制御を他のURLに転送したりといったことが考えられます。

開発者のアプリケーションへのTwilioからのリクエスト

Twilioは通常のWebブラウザー同様、application/x-www-form-urlencoded形式でHTTPリクエストをユーザーのアプリケーションに送信します。 (Twilioが)このリクエストにパラメーターと値を含めることで、Twilioはユーザーのアプリケーションにデータを送信し、これを使用してレスポンスの前に処理を行うことができます。

アカウントポータルREST APIを使用して、Twilioがリクエストを送信する際に使用するURLとHTTPメソッドを構成することができます。

TwilioはPOSTリクエストをキャッシュできません。 Twilioに静的なTwiMLページをキャッシュさせたい場合は、GETを使用してTwilioからリクエストを送信させるようにしてください。

ユーザーのTwilio電話番号またはChannelからメッセージが受信されると、同期HTTPリクエストがその番号またはChannelで構成されたメッセージURLに対して送信され、そのレスポンスとしてTwiMLの受信が想定されます。

Twilioはリクエストと一緒に下記のパラメーターを構成したHTTPメソッドに応じて、POSTパラメーターまたはURLクエリーパラメーターとして送信します。

リクエストパラメーター

パラメーター 説明
Message SID このメッセージの 34 文字のユニークな識別子です。 後で REST API を使ってこのメッセージを取得する時に使えます。
SmsSid MessageSidと同様の値。廃止される予定、後方互換のために用意されています。
AccountSid このメッセージの関連づけられているアカウントの34文字のIDです。
MessagingServiceSid このメッセージに関連づけられているMessaging Serviceの34文字のIDです。
From このメッセージの送信された電話番号またはChannelアドレスです。
To 受信者の電話番号またはChannelアドレスです。
Body テキストの本文メッセージ。最大1600文字までです。
NumMedia メッセージに関連付けられたメディアアイテムの数です。

メッセージに関連付けられた画像のようなメディアがある場合、Twilioは下記のパラメーターも送信します。

パラメーター 説明
MediaContentType{N} MediaUrl{N}に保存されたメディアのContentTypesです。 MediaContentType{N}の順番は、MediaUrl{N}の順番と一致します。 MediaContentType{N}の順番は、MediaUrl{N}の順番と一致します。 MediaContentType{N}が使用されるのではなく、NumMediaによって複数のメディア要素が含まれている場合、Nはメディアの0で始まるインデックス値となります(たとえば、​MediaContentType0となります)。
MediaUrl{N} メッセージで受信されたメディアの内容を参照するURLです。 MediaContentType{N}が使用されるのではなく、NumMediaによって複数のメディア要素が含まれている場合、Nはメディアの0で始まるインデックス値となります(たとえば、​MediaUrl0となります。)

Twilioは From と To の電話番号から、場所の検索も行います。 次のパラメーターが存在する場合、Twlilio はこれらのパラメーターを送信します。

パラメーター 説明
FromCity 送信者の都市名です。
FromState 送信者の州名です。
FromZip 送信者の郵便番号です。
FromCountry 送信者の国名です。
ToCity 相手の都市名です。
ToState 相手の州名です。
ToZip 相手の郵便番号です。
ToCountry 相手の国名です。

「STOP」とオプトアウト

Twilioはすべてのロングコードの電話番号のオプトアウトを、業界標準に則って処理します。 

オプトアウト用のキーワードは開発者のアプリケーションに渡され、エンドユーザーがオプトアウトしたことを知らせます。 そのエンドユーザーに今後送信される全メッセージはエラーとなります。 また「Start」および「Yes」キーワードもアプリケーションに渡され、これによりエンドユーザーは再びメッセージを受信できるようになります。

ユーザーがメッセージングサービスに登録されている電話番号からオプトアウトした場合、その特定のメッセージングサービスから送信されるすべてのメッセージの受信もオプトアウトすることになります。

データフォーマット

電話番号

可能な場合、Twilioからのリクエスト中のすべての電話番号はE.164形式となります。 たとえば、「080-1234-5678」は「+818012345678」となります。 しかし、まれにTwilioが着信時の発信者IDをE.164に変換できない場合があります。 このような場合、Twilioは発信者IDの文字列をそのまま通知します。

日付と時間

Twilio空のリクエスト内のすべての日付と時刻にはRFC 2822形式のGMTが使用されます。 たとえば、日本時間で2010年8月20日の午前10時13分は、「Fri, 20 Aug 2010 01:13:42 +0000」として表されます。

Twilioにレスポンスを返す

Twilio電話番号のひとつでメッセージが受信されると、Twilioはその番号に対して構成されたメッセージURLにHTTPリクエストを発行します。

そのリクエストへのレスポンスとして、Twilioに対してメッセージへの応答としてどんなことを行うのか伝えることができます。 電話番号のURLはこちらで構成できます。

Twilioはお行儀のよいHTTPクライアントです

Twilio は通常のウェブ ブラウザと同じように振る舞いますので、新しいことを覚える必要はありません。

  • Cookie: 通常のWebブラウザーと同様、TwilioはHTTP Cookieを受け入れ、これらを (Twilioからの) 各リクエストに追加します。
  • リダイレクト: こちらも通常のWebブラウザーと同様、HTTPリダイレクト (HTTPステータスコード301、307、など) に従います。
  • キャッシュ: こちらも通常のWebブラウザーと同様、HTTPヘッダーで許可されており (ETagおよびLast-Modifiedヘッダー) 、かつHTTPメソッドがGETである場合、Twilioはファイルのキャッシュを行います。

Cookie

Twilio は、2 つの電話番号の間でやり取りされる複数の SMS をまたいで cookie の状態を保持します。 このため、複数のメッセージを 1 つの会話として扱うことができ、その会話のセッション識別子などのデータを cookie に格納して、後で使用できます。 この会話の cookie は、4 時間使用しないと期限切れになります。

MIME Type に対応

Twilio はユーザー アプリケーションのレスポンスの MIME Type に応じて異なる動作をします。

MIME Type 動作
text/xml, application/xml, text/html Twilioは返されたドキュメントをTwiML XMLの命令セットとして解釈します。 これはもっとも一般的に使用されるレスポンスです。
text/plain Twilioはメッセージ中にある送信者にテキストファイルの内容を返します。

TwilioのTwiMLインタープリターの仕組み

開発者のアプリケーションがTwilioからのリクエストにレスポンスを送信する際、TwilioはTwiMLインタープリターを使用して受信したドキュメントを実行します。 物事が複雑化しないよう、TwiMLインタープリターは特別に名前の付けられた、わずかなXML要素のみを解釈します。 TwiMLの用語では、これらは3つのグループに分類されます。 ルートの <Response> 要素、verbs (動詞) 、そして nouns (名詞) です。 各グループについて下記で解説していきます。

インタープリターはTwiMLドキュメントを上から下に見て動詞を順番に実行します。例として下記のTwiMLメッセージはhttps://demo.twilio.com/sms/welcomeにコントロールをリダイレクトする前に"Hello World" を送信者に返信します。

<?xml version="1.0" encoding="UTF-8" ?>
<Response>
    <Message>Hello World!</Message>
    <Redirect>https://demo.twilio.com/sms/welcome</Redirect>
</Response>

複数の<Message>動詞をひとつのTwiML文書に指定すると複数のメッセージを送信可能です。 以下に例を示します:

<?xml version="1.0" encoding="UTF-8" ?>
<Response>
    <Message>This is message 1 of 2.</Message>
    <Message>This is message 2 of 2.</Message>
</Response>

 

TwiML要素 (「動詞」および「名詞」) の名前は大文字と小文字を区別します。 たとえば、<Message> の代わりに <message> を使用するとエラーになります。 属性名もまた大文字と小文字を区別し、キャメルケース形式を使用します。 XMLのコメントを自由に使用でき、これらはインタープリターによって無視されます。

<Response>要素

Twilioの XMLマークアップにおけるルート要素は<Response>要素です。 Twilioのリクエストに対するTwiMLレスポンスでは、すべての動詞はこの要素内に入れ子にされていることが必要です。 他のいかなる構造も無効とみなされます。

 

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>I'm hungry!</Message>
</Response>

TwiMLメッセージング動詞

TwiMLドキュメントで最も使われるXMLエレメントはTwiML動詞です。動詞名は大文字小文字を区別します、属性名も同様です。一つのコアTwiMLメッセージ動詞と一つの第二動詞です。それぞれを詳しい説明があります。コア動詞は

  • <Message>到着したメッセージに返信をする。

制御フローが他のドキュメントに渡されるために、TwiMLドキュメントの一部の動詞に到達できない特定のケースがあります。 これは通常、動詞の「action」属性が設定されている場合に起こります。

たとえば、<Message> の後に <Redirect> が続く場合、<Message> 動詞の「action」URLが設定されていると <Redirect> には到達できなくなります。 このような場合、SMSセッションのフローは「action」URLのリクエストに対するレスポンスで受け取ったTwiMLで継続されます。

以下の動詞は制御フローに影響を与える可能性があります: <Message><Redirect>

TwiML名詞

TwiMLの名詞は、動詞の内部に入れ子にされたもののことを指し、これには動詞自身は含まれません。 これは動詞の作用する対象を指します。 これは通常テキストです。 しかし時には、<Media> および <Body> 名詞を伴う <Message> のように、名詞となる入れ子にされたXML要素が伴うこともあります。

ステータスコールバック

ステータスコールバックはアプリケーションフローを制御しないため、TwiMLを返す必要はありませんが、ステータスコールバックには 204 No Content または Content-Type: text/xml と空の <Response/> を含むBodyを伴った 200 OK のいずれかでレスポンスを行うことを推奨します。 正しくレスポンスを返さない場合、デバッガーで警告が発生します。

Twilioヘルパーライブラリーを使用したTwiMLの生成

Twilioでは、皆さんの使い慣れたプログラミング言語でTwiMLを生成するためのヘルパーライブラリーを用意しています。

コードサンプルを読み込んでいます...
Language
SDKバージョン:
  • 5.x
SDKバージョン:
  • 7.x
SDKバージョン:
  • 3.x
SDKバージョン:
  • 5.x
SDKバージョン:
  • 6.x
SDKバージョン:
  • 5.x
形式:
  • TwiML
const MessagingResponse = require('twilio').twiml.MessagingResponse;

const response = new MessagingResponse();
const message = response.message();
message.body('Hello World!');
response.redirect('https://demo.twilio.com/welcome/sms/');

console.log(response.toString());
using Twilio.TwiML;
using Twilio.TwiML.Messaging;
using System;


class Example
{
    static void Main()
    {
        var response = new MessagingResponse();
        var message = new Message();
        message.Body("Hello World!");
        response.Append(message);
        response.Redirect(url: new Uri("https://demo.twilio.com/welcome/sms/"));

        Console.WriteLine(response.ToString());;
    }
}
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$message = $response->message();
$message->body('Hello World!');
$response->redirect('https://demo.twilio.com/welcome/sms/');

echo $response;
require 'twilio-ruby'

response = Twilio::TwiML::MessagingResponse.new
response.message do |message|
  message.body('Hello World!')
end
response.redirect('https://demo.twilio.com/welcome/sms/')

puts response
from twilio.twiml.messaging_response import Body, Message, Redirect, MessagingResponse

response = MessagingResponse()
message = Message()
message.body('Hello World!')
response.append(message)
response.redirect('https://demo.twilio.com/welcome/sms/')

print(response)
import com.twilio.twiml.messaging.Body;
import com.twilio.twiml.messaging.Message;
import com.twilio.twiml.voice.Redirect;
import com.twilio.twiml.MessagingResponse;
import com.twilio.twiml.TwiMLException;


public class Example {
    public static void main(String[] args) {
        Body body = new Body("Hello World!");
        Message message = new Message.Builder().body(body).build();
        Redirect redirect = new Redirect.Builder()
            .url("https://demo.twilio.com/welcome/sms/").build();
        MessagingResponse response = new MessagingResponse.Builder()
            .message(message).redirect(redirect).build();

        try {
            System.out.println(response.toXml());
        } catch (TwiMLException e) {
            e.printStackTrace();
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message><Body>Hello World!</Body></Message>
    <Redirect>https://demo.twilio.com/welcome/sms/</Redirect>
</Response>
Hello Worldという本文を送信し、TwiMLに制御をリダイレクトする
コードサンプルを読み込んでいます...
Language
SDKバージョン:
  • 5.x
SDKバージョン:
  • 7.x
SDKバージョン:
  • 3.x
SDKバージョン:
  • 5.x
SDKバージョン:
  • 6.x
SDKバージョン:
  • 5.x
形式:
  • TwiML
const MessagingResponse = require('twilio').twiml.MessagingResponse;

const response = new MessagingResponse();
response.message('This is message 1 of 2.');
response.message('This is message 2 of 2.');

console.log(response.toString());
using Twilio.TwiML;
using System;


class Example
{
    static void Main()
    {
        var response = new MessagingResponse();
        response.Message("This is message 1 of 2.");
        response.Message("This is message 2 of 2.");

        Console.WriteLine(response.ToString());;
    }
}
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$response->message('This is message 1 of 2.');
$response->message('This is message 2 of 2.');

echo $response;
require 'twilio-ruby'

response = Twilio::TwiML::MessagingResponse.new
response.message(body: 'This is message 1 of 2.')
response.message(body: 'This is message 2 of 2.')

puts response
from twilio.twiml.messaging_response import Message, MessagingResponse

response = MessagingResponse()
response.message('This is message 1 of 2.')
response.message('This is message 2 of 2.')

print(response)
import com.twilio.twiml.messaging.Body;
import com.twilio.twiml.messaging.Message;
import com.twilio.twiml.MessagingResponse;
import com.twilio.twiml.TwiMLException;


public class Example {
    public static void main(String[] args) {
        Body body = new Body("This is message 1 of 2.");
        Message message = new Message.Builder().body(body).build();
        Body body2 = new Body("This is message 2 of 2.");
        Message message2 = new Message.Builder().body(body2).build();
        MessagingResponse response = new MessagingResponse.Builder()
            .message(message).message(message2).build();

        try {
            System.out.println(response.toXml());
        } catch (TwiMLException e) {
            e.printStackTrace();
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>This is message 1 of 2.</Message>
    <Message>This is message 2 of 2.</Message>
</Response>
メッセージを2件送信する

ヘルプが必要ですか?

誰しもが一度は考える「コーディングって難しい」。そんな時は、お問い合わせフォームから質問してください。 または、Stack Overflow でTwilioタグのついた情報から欲しいものを探してみましょう。

コードサンプルを読み込んでいます...
SDKバージョン:
  • 5.x
SDKバージョン:
  • 7.x
SDKバージョン:
  • 3.x
SDKバージョン:
  • 5.x
SDKバージョン:
  • 6.x
SDKバージョン:
  • 5.x
形式:
  • TwiML
const MessagingResponse = require('twilio').twiml.MessagingResponse;

const response = new MessagingResponse();
const message = response.message();
message.body('Hello World!');
response.redirect('https://demo.twilio.com/welcome/sms/');

console.log(response.toString());
using Twilio.TwiML;
using Twilio.TwiML.Messaging;
using System;


class Example
{
    static void Main()
    {
        var response = new MessagingResponse();
        var message = new Message();
        message.Body("Hello World!");
        response.Append(message);
        response.Redirect(url: new Uri("https://demo.twilio.com/welcome/sms/"));

        Console.WriteLine(response.ToString());;
    }
}
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$message = $response->message();
$message->body('Hello World!');
$response->redirect('https://demo.twilio.com/welcome/sms/');

echo $response;
require 'twilio-ruby'

response = Twilio::TwiML::MessagingResponse.new
response.message do |message|
  message.body('Hello World!')
end
response.redirect('https://demo.twilio.com/welcome/sms/')

puts response
from twilio.twiml.messaging_response import Body, Message, Redirect, MessagingResponse

response = MessagingResponse()
message = Message()
message.body('Hello World!')
response.append(message)
response.redirect('https://demo.twilio.com/welcome/sms/')

print(response)
import com.twilio.twiml.messaging.Body;
import com.twilio.twiml.messaging.Message;
import com.twilio.twiml.voice.Redirect;
import com.twilio.twiml.MessagingResponse;
import com.twilio.twiml.TwiMLException;


public class Example {
    public static void main(String[] args) {
        Body body = new Body("Hello World!");
        Message message = new Message.Builder().body(body).build();
        Redirect redirect = new Redirect.Builder()
            .url("https://demo.twilio.com/welcome/sms/").build();
        MessagingResponse response = new MessagingResponse.Builder()
            .message(message).redirect(redirect).build();

        try {
            System.out.println(response.toXml());
        } catch (TwiMLException e) {
            e.printStackTrace();
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message><Body>Hello World!</Body></Message>
    <Redirect>https://demo.twilio.com/welcome/sms/</Redirect>
</Response>
SDKバージョン:
  • 5.x
SDKバージョン:
  • 7.x
SDKバージョン:
  • 3.x
SDKバージョン:
  • 5.x
SDKバージョン:
  • 6.x
SDKバージョン:
  • 5.x
形式:
  • TwiML
const MessagingResponse = require('twilio').twiml.MessagingResponse;

const response = new MessagingResponse();
response.message('This is message 1 of 2.');
response.message('This is message 2 of 2.');

console.log(response.toString());
using Twilio.TwiML;
using System;


class Example
{
    static void Main()
    {
        var response = new MessagingResponse();
        response.Message("This is message 1 of 2.");
        response.Message("This is message 2 of 2.");

        Console.WriteLine(response.ToString());;
    }
}
<?php
require_once './vendor/autoload.php';
use Twilio\Twiml;

$response = new Twiml();
$response->message('This is message 1 of 2.');
$response->message('This is message 2 of 2.');

echo $response;
require 'twilio-ruby'

response = Twilio::TwiML::MessagingResponse.new
response.message(body: 'This is message 1 of 2.')
response.message(body: 'This is message 2 of 2.')

puts response
from twilio.twiml.messaging_response import Message, MessagingResponse

response = MessagingResponse()
response.message('This is message 1 of 2.')
response.message('This is message 2 of 2.')

print(response)
import com.twilio.twiml.messaging.Body;
import com.twilio.twiml.messaging.Message;
import com.twilio.twiml.MessagingResponse;
import com.twilio.twiml.TwiMLException;


public class Example {
    public static void main(String[] args) {
        Body body = new Body("This is message 1 of 2.");
        Message message = new Message.Builder().body(body).build();
        Body body2 = new Body("This is message 2 of 2.");
        Message message2 = new Message.Builder().body(body2).build();
        MessagingResponse response = new MessagingResponse.Builder()
            .message(message).message(message2).build();

        try {
            System.out.println(response.toXml());
        } catch (TwiMLException e) {
            e.printStackTrace();
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>This is message 1 of 2.</Message>
    <Message>This is message 2 of 2.</Message>
</Response>