Giter VIP home page Giter VIP logo

Comments (5)

eric-brechemier avatar eric-brechemier commented on June 14, 2024

Warning

The documentation of the transcribeCallback attribute warns that:

The transcribeCallback URL attribute is considered Not PII.

but the Voicemail Twimlet does include the Email value which is Personally Identifiable Information (PII) as parameter in the URL.

The linked page further explains that:

You should take care not to place PII in fields with this designation. Twilio does not treat this data as PII, and its value may be visible to Twilio employees, stored long-term, and may continue to be stored after you’ve left Twilio’s platform.

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 14, 2024

Annotated Source Code

based on a snapshot of Voicemail TwiML source code (voicemail.php)
sent to me by Twilio support by email on 2019-07-08

This is PHP code.

<?php

It is shared by Twilio under the MIT license.

/*
Copyright (c) 2012 Twilio, Inc.

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

It uses the (deprecated) class Twilio\Twiml of the twilio-php helper library to generate TwiML.

use Twilio\Twiml;

Define a black list with a single email. This will not be necessary using Twilio Functions, which are bound to a specific Twilio account.

// Temporary Hack: FIX ME MONDAY
$emailBlacklist = array('[REDACTED]@yahoo.com');

Define a utility to format a phone number for display. Used in the email which notifies that a voicemail has been recorded.

function PhoneFormat($no) {

	$no = Validation::StripNonNumeric($no);

	if (strlen($no) == 11 && substr($no, 0, 1) == '1') {
		$no = substr($no, 1);
	} elseif (strlen($no) == 12 && substr($no, 0, 2) == '+1') {
		$no = substr($no, 2);
	}

	if (strlen($no) == 10) {
		return '(' . substr($no, 0, 3) . ') ' . substr($no, 3, 3) . '-' . substr($no, 6);
	} elseif (strlen($no) == 7) {
		return substr($no, 0, 3) . '-' . substr($no, 3);
	} else {
		return $no;
	}

}

Start a new TwiML document.

// initiate response library
$response = new Twiml();

Define email headers. Used when the email is sent, with or without a transcription.

// setup from email headers
$headers = 'From: [email protected]' . "\r\n" .
		   'Reply-To: [email protected]' . "\r\n" .
		   'X-Mailer: Twilio Twimlets';

Get the number of the caller and the recipient.
Note: the number of the recipient is unused.

// grab the to and from phone numbers
$from = strlen($_REQUEST['From']) ? $_REQUEST['From'] : $_REQUEST['Caller'];
$to = strlen($_REQUEST['To']) ? $_REQUEST['To'] : $_REQUEST['Called'];

Stage 0: Black List

When the Email is found in the black list, just hang up.

if (in_array($_GET['Email'], $emailBlacklist)) {
	$response->hangup();
	if (!headers_sent()) {
		header('Content-type: text/xml');
	}
	echo $response;
	die;
}

Stage 3

// check transcription response
if (strtolower($_REQUEST['TranscriptionStatus']) == 'completed') {

	// email message with the text of the transcription and a link to the audio recording
	$body = "You have a new voicemail from " . PhoneFormat($from) . "\n\n";
	$body .= "Text of the transcribed voicemail:\n{$_REQUEST['TranscriptionText']}.\n\n";
	$body .= "Click this link to listen to the message:\n{$_REQUEST['RecordingUrl']}.mp3";

	mail($_GET['Email'], "New Voicemail Message from " . PhoneFormat($from), $body, $headers);
	die;

} else if (strtolower($_REQUEST['TranscriptionStatus']) == 'failed') {

	// transcription failed so just email message with just a link to the audio recording
	$body = "You have a new voicemail from " . PhoneFormat($from) . "\n\n";
	$body .= "Click this link to listen to the message:\n{$_REQUEST['RecordingUrl']}.mp3";

	mail($_GET['Email'], "New Voicemail Message from " . PhoneFormat($from), $body, $headers);
	die;

Stage 2

} else if (strlen($_REQUEST['RecordingUrl'])) {

	// returning from the Record so hangup
	$response->say('Thanks. Good bye.');
	$response->hangup();

	// not transcribing, email message with a link to the audio recording
	if (strlen($_GET['Transcribe']) && strtolower($_GET['Transcribe']) != 'true') {
		$body = "You have a new voicemail from " . PhoneFormat($from) . "\n\n";
		$body .= "Click this link to listen to the message:\n{$_REQUEST['RecordingUrl']}.mp3";

		mail($_GET['Email'], "New Voicemail Message from " . PhoneFormat($from), $body, $headers);
	}

Stage 1

} else {

	// no message has been received, so play a VM greeting

	// figure out the message to say or play before the recording
	// first, check to see if we have an http URL (simple check)
	if (strtolower(substr(trim($_GET['Message']), 0, 4)) == 'http') {
		$response->play($_GET['Message']);
	}

	// check if we have any message, if so, read it back
	elseif (strlen(trim($_GET['Message']))) {
		$response->say(stripslashes($_GET['Message']));
	}

	// no message, just use a default
	else {
		$response->say('Please leave a message after the beep.');
	}

	// record with / without transcription
	if ((!strlen($_GET['Transcribe'])) || strtolower($_GET['Transcribe']) == 'true') {
		$params = array(
			'transcribe' => 'true',
			'transcribeCallback' => $_SERVER['SCRIPT_URI'] . '?Email=' . $_GET['Email'],
		);
	} else {
		$params = array();
	}

	// add record with the specified params
	$response->record($params);

}

Send the XML content-type header and the TwiML body.

// send the response
if (!headers_sent()) {
	header('Content-type: text/xml');
}
echo $response;

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 14, 2024

Test Cases

[VOICEMAIL-1-1] Voicemail with Default Message

Input

Parameter Value
Email [email protected]
Transcribe false

Output

$ curl -s 'https://twimlets.com/voicemail?Email=you%40example.com&Transcribe=false' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say>Please leave a message after the beep.</Say>
  <Record/>
</Response>

[VOICEMAIL-1-2] Voicemail with Custom Text Message

Input

Parameter Value
Email [email protected]
Message Custom message
Transcribe false

Output

$ curl -s 'https://twimlets.com/voicemail?Email=you%40example.com&Message=Custom%20message&Transcribe=false' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say>Custom message</Say>
  <Record/>
</Response>

[VOICEMAIL-1-3] Voicemail with Recorded Message

Input

Parameter Value
Email [email protected]
Message https://example.com/recorded-message.mp3
Transcribe false

Output

$ curl -s 'https://twimlets.com/voicemail?Email=you%40example.com&Message=https%3A%2F%2Fexample.com%2Frecorded-message.mp3&Transcribe=false' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Play>https://example.com/recorded-message.mp3</Play>
  <Record/>
</Response>

[VOICEMAIL-1-4] Voicemail with Text Transcription

Input

Parameter Value
Email [email protected]

Output

$ curl -s 'https://twimlets.com/voicemail?Email=you%40example.com' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say>Please leave a message after the beep.</Say>
  <Record transcribe="true" transcribeCallback="http://twimlets.com/[email protected]"/>
</Response>

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 14, 2024

[VOICEMAIL-2-1] Recording Callback Without Transcription

Input

Parameter Value
RecordingUrl https://twilio.example.com/voicemail-recording
From +1-916-555-0123
Email [email protected]
Transcribe false

Output

$ curl -s 'https://twimlets.com/voicemail?RecordingUrl=https%3A%2F%2Ftwilio.example.com%2Fvoicemail-recording&From=%2B1-916-555-0123&Email=you%40example.com&Transcribe=false' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say>Thanks. Good bye.</Say>
  <Hangup/>
</Response>

Also, when there is no transcription requested, an email is expected to be sent to the provided Email address:

Date: Wed, 17 Jul 2019 18:27:47 +0000 (UTC)
To: [email protected]
Subject: New Voicemail Message from (916) 555-0123
From: [email protected]
Reply-To: [email protected]
X-Mailer: Twilio Twimlets
Content-type: multipart/alternative; boundary="----------=_1563388067-20691-604"

This is a multi-part message in MIME format...

------------=_1563388067-20691-604

You have a new voicemail from (916) 555-0123

Click this link to listen to the message:
https://links.twiliocdn.com/wf/click?upn=9ue0i4-2FBDXNf3UebS-2FYu6traHNQXQoxNUIPOGaEldg4DF6CZZtXgypcID470M8fKIjbg-2B5bIqEYgRq2e09sEfQ-3D-3D_00wESb-2FEGuldVW-2BBvA7Jf-2Fvcp7ul4DmeNzvnwlQr5T0c5tA57my-2FoLT-2B2zmw-2FxekCrerAyiZ4JcsRJzWjauPImQFDO61zKvPe2QACmOD6QMTrxZ-2FxFyXQT8ZxI7jXqcgO1A89zzaZGM3W-2BKXJVssf-2FqXo2NhZ95Izhn0yhi0mXA33hT9A-2F8Db4rEuK8UGjf7evcPZ6B9pQvi8psVSPejU7XtYO1tXaVpgPns81kZy8o-3D

------------=_1563388067-20691-604
Content-Type: text/html
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

<html><body>
<p>You have a new voicemail from (916) 555-0123</p>
<p>Click this link to listen to the message: <a href=3D"https://links.twili=
ocdn.com/wf/click?upn=3D9ue0i4-2FBDXNf3UebS-2FYu6traHNQXQoxNUIPOGaEldg4DF6C=
ZZtXgypcID470M8fKIjbg-2B5bIqEYgRq2e09sEfQ-3D-3D_00wESb-2FEGuldVW-2BBvA7Jf-2=
Fvcp7ul4DmeNzvnwlQr5T0c5tA57my-2FoLT-2B2zmw-2FxekCrerAyiZ4JcsRJzWjauPIgidgL=
e-2BpbiuQJ4ECfoFW-2BwF8fAiRYD3KPMq8E9FefMsBxQTtJB-2FMOWnd5rvA98-2BpU4EsJB6Z=
A4fkeefdN-2BFHuVlZZFZhgFWHqo94cFn0e8j6VlcsTuVRAAVvJdYdCpd3bwAgj5a2sMdVlonm8=
pKBKA-3D">https://twilio.example.com/voicemail-recording.mp3</a></p>

<img src=3D"https://links.twiliocdn.com/wf/open?upn=3D00wESb-2FEGuldVW-2BBv=
A7Jf-2Fvcp7ul4DmeNzvnwlQr5T0c5tA57my-2FoLT-2B2zmw-2FxekCrerAyiZ4JcsRJzWjauP=
IostBcmTEQD5Lbt5wtEplkhlkrvGzzvlH0ceQjJuz2tDME-2FE374VzlG8538KFot4Utayc3Nen=
zxd-2FBhv-2FrBf6Dy1TBGGPhrKWoS-2BRbjsHMeA3UrFF1q1bQvcY6IFp3xOUestVZK1JRBeqs=
7RYJ9gxqY-3D" alt=3D"" width=3D"1" height=3D"1" border=3D"0" style=3D"heigh=
t:1px !important;width:1px !important;border-width:0 !important;margin-top:=
0 !important;margin-bottom:0 !important;margin-right:0 !important;margin-le=
ft:0 !important;padding-top:0 !important;padding-bottom:0 !important;paddin=
g-right:0 !important;padding-left:0 !important;"/>
</body></html>

------------=_1563388067-20691-604--

Note that the email has been filtered and transformed before being sent, with the link rewritten to pass through a proxy with a tracking ID, and an HTML version of the text added. The link to the recording is used as text for the link in the HTML version. You can check that the .mp3 extension was added as expected: (...)>https://twilio.example.com/voicemail-recording.mp3</a>.

[VOICEMAIL-2-2] Recording Callback With Transcription

Input

Parameter Value
RecordingUrl https://twilio.example.com/voicemail-recording
Email [email protected]
Transcribe true

Output

$ curl -s 'https://twimlets.com/voicemail?RecordingUrl=https%3A%2F%2Ftwilio.example.com%2Fvoicemail-recording&Email=you%40example.com' \
| xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say>Thanks. Good bye.</Say>
  <Hangup/>
</Response>

In this case, no email is sent at this stage.

from function-templates.

eric-brechemier avatar eric-brechemier commented on June 14, 2024

[VOICEMAIL-3-1] Transcription Successful

Input

Parameter Value
TranscriptionStatus completed
TranscriptionText Call me
RecordingUrl https://twilio.example.com/voicemail-recording
From +1-916-555-0123
Email [email protected]

Output

$ curl -s 'https://twimlets.com/voicemail?TranscriptionStatus=completed&TranscriptionText=Call%20me&RecordingUrl=https%3A%2F%2Ftwilio.example.com%2Fvoicemail-recording&From=%2B1-916-555-0123=&Email=you%40example.com'

The output is empty, but an email is expected to be sent to the provided Email address:

To: [email protected]
Subject: New Voicemail Message from (916) 555-0123
From: [email protected]
Reply-To: [email protected]
X-Mailer: Twilio Twimlets
Content-type: multipart/alternative; boundary="----------=_1563388872-22825-231"

This is a multi-part message in MIME format...

------------=_1563388872-22825-231

You have a new voicemail from (916) 555-0123

Text of the transcribed voicemail:
Call me.

Click this link to listen to the message:
https://links.twiliocdn.com/wf/click?upn=9ue0i4-2FBDXNf3UebS-2FYu6traHNQXQoxNUIPOGaEldg4DF6CZZtXgypcID470M8fKIjbg-2B5bIqEYgRq2e09sEfQ-3D-3D_00wESb-2FEGuldVW-2BBvA7Jf-2Fvcp7ul4DmeNzvnwlQr5T2rxxAtPU863zWOIsn43ic6MkOFiha0GINOPSHKrgOtSJEbZ8WAXT7ZTAXUpc1uiJUZxVvasXzSSyqMgtZwUdfHPJV1ydv0zjsUt7OdIVk4feAbzqnJ0hmT10Es-2B072xP-2FkeS1EBCpnDZkwqbcD7IwI5o-2B8qIWMM0rzaPSZJ5vZwvioaIZe99q0emGFrWOjlVI-3D

------------=_1563388872-22825-231
Content-Type: text/html
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

<html><body>
<p>You have a new voicemail from (916) 555-0123</p>
<p>Text of the transcribed voicemail: Call me.</p>
<p>Click this link to listen to the message: <a href=3D"https://links.twili=
ocdn.com/wf/click?upn=3D9ue0i4-2FBDXNf3UebS-2FYu6traHNQXQoxNUIPOGaEldg4DF6C=
ZZtXgypcID470M8fKIjbg-2B5bIqEYgRq2e09sEfQ-3D-3D_00wESb-2FEGuldVW-2BBvA7Jf-2=
Fvcp7ul4DmeNzvnwlQr5T2rxxAtPU863zWOIsn43ic6MkOFiha0GINOPSHKrgOtSMAvmosaH8zv=
WsNMkYYNaRLBTOIFLg9uHsR4LO6QCZyoMOVtjE-2Ff0Vz24Ja-2FFCIW3spx6U9xqrgLf-2B9Aw=
2qsTBgzeL3VmwOlwRtW-2BcG4BYpGg1hr6yyxMOa4qd4dKtGwJt38WLEn8VNj0MiX80JkCi4-3D=
">https://twilio.example.com/voicemail-recording.mp3</a></p>

<img src=3D"https://links.twiliocdn.com/wf/open?upn=3D00wESb-2FEGuldVW-2BBv=
A7Jf-2Fvcp7ul4DmeNzvnwlQr5T2rxxAtPU863zWOIsn43ic6MkOFiha0GINOPSHKrgOtSN-2BB=
QpDwA3xX9yJSe-2Ff8CkAzlpZuUwWCshGd23jOrQUEV8krpyK73FDlHQghKPd6jNpuMXEguiVm1=
3LLonhuykE6VUZ1olP9ifK8PnJqaLn5WXA-2Fy9FtdyHyaRet5MHMGvMlZbTaQgtMHWcSIy0aOR=
s-3D" alt=3D"" width=3D"1" height=3D"1" border=3D"0" style=3D"height:1px !i=
mportant;width:1px !important;border-width:0 !important;margin-top:0 !impor=
tant;margin-bottom:0 !important;margin-right:0 !important;margin-left:0 !im=
portant;padding-top:0 !important;padding-bottom:0 !important;padding-right:=
0 !important;padding-left:0 !important;"/>
</body></html>

------------=_1563388872-22825-231--

[VOICEMAIL-3-2] Transcription Failed

When the transcription fails, an email without the transcription is sent, in the same format as when no transcription has been requested; see test case [VOICEMAIL-2-1].

Input

Parameter Value
TranscriptionStatus failed
RecordingUrl https://twilio.example.com/voicemail-recording
From +1-916-555-0123
Email [email protected]

Output

$ curl -s 'https://twimlets.com/voicemail?TranscriptionStatus=failed&RecordingUrl=https%3A%2F%2Ftwilio.example.com%2Fvoicemail-recording&From=%2B1-916-555-0123=&Email=you%40example.com'

Here again, the output is empty, and an email is expected to be sent to the provided Email address:

Date: Wed, 17 Jul 2019 18:51:04 +0000 (UTC)
To: [email protected]
Subject: New Voicemail Message from (916) 555-0123
From: [email protected]
Reply-To: [email protected]
X-Mailer: Twilio Twimlets
Content-type: multipart/alternative; boundary="----------=_1563389464-20716-397"

This is a multi-part message in MIME format...

------------=_1563389464-20716-397

You have a new voicemail from (916) 555-0123

Click this link to listen to the message:
https://links.twiliocdn.com/wf/click?upn=9ue0i4-2FBDXNf3UebS-2FYu6traHNQXQoxNUIPOGaEldg4DF6CZZtXgypcID470M8fKIjbg-2B5bIqEYgRq2e09sEfQ-3D-3D_00wESb-2FEGuldVW-2BBvA7Jf-2Fvcp7ul4DmeNzvnwlQr5T0OWTqg9iAwbT6vKEbYp5s8FMn7cWT6-2BcZWCInPHyXevhFfa8G-2FoogCEMYrOMhLynoRywd18UaZ8DUhZVOWl8-2BeJukzJTtwgxGyeTcEz-2FXuXqQNhyvQ9u2Jh1UbjwdA5tM5Rko0vD0MiKXKBfXZSFHp91GWpRMqIEk8X7qBZiD7IEzKBHE7X-2BRMMkSVRg4jG9Y-3D

------------=_1563389464-20716-397
Content-Type: text/html
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

<html><body>
<p>You have a new voicemail from (916) 555-0123</p>
<p>Click this link to listen to the message: <a href=3D"https://links.twili=
ocdn.com/wf/click?upn=3D9ue0i4-2FBDXNf3UebS-2FYu6traHNQXQoxNUIPOGaEldg4DF6C=
ZZtXgypcID470M8fKIjbg-2B5bIqEYgRq2e09sEfQ-3D-3D_00wESb-2FEGuldVW-2BBvA7Jf-2=
Fvcp7ul4DmeNzvnwlQr5T0OWTqg9iAwbT6vKEbYp5s8FMn7cWT6-2BcZWCInPHyXevj02HPoC-2=
FddzzqmsjLaEPn7rlRVD08u9IYPK8h0jsO3QJHaf1QFuV2uW9RBMFUYP9-2B4v3PXEMiril0IAz=
x8hrvg6V2oOyEvTrYmcE810PSqq4EMoiurP1ngCuunv-2BjooWFwqDexSG6Bn9aGe5iVhahU-3D=
">https://twilio.example.com/voicemail-recording.mp3</a></p>

<img src=3D"https://links.twiliocdn.com/wf/open?upn=3D00wESb-2FEGuldVW-2BBv=
A7Jf-2Fvcp7ul4DmeNzvnwlQr5T0OWTqg9iAwbT6vKEbYp5s8FMn7cWT6-2BcZWCInPHyXevq02=
G7d6MSJgam1eNev0-2BcATr14N3QlF2f-2F3PY-2FZ1OW3mZzCwlYfxq2u0cGvqqOijeptvtOBw=
mSlzl4ofpgYr-2FqtP2vW3KVFLYDG50LwXssLPhgoFsg6hx8WaK3b3lZvLWnwbPyhQMswjYihLy=
-2FNIX8-3D" alt=3D"" width=3D"1" height=3D"1" border=3D"0" style=3D"height:=
1px !important;width:1px !important;border-width:0 !important;margin-top:0 =
!important;margin-bottom:0 !important;margin-right:0 !important;margin-left=
:0 !important;padding-top:0 !important;padding-bottom:0 !important;padding-=
right:0 !important;padding-left:0 !important;"/>
</body></html>

------------=_1563389464-20716-397--

from function-templates.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.