Voicemail is a telephony application with which everyone is familiar. Twilio makes building a voicemail system simple, and makes integrating it with the web or other messaging technologies just as straight forward. This recipe will describe the building of a simple voicemail box application.
A voicemail system consists of two applications. One application allows people to record messages and leave them in a mailbox. The other application allows the owner of the mailbox to listen to and manage the messages he has received. This system assigns each mailbox an extension and a passcode and has two entry points, one for leaving messages and one for checking them. If you were to integrate this into your own system or the Company Directory recipe, you would most likely wire the entry points into your own application, bypassing the step where you ask the caller for their mailbox extension.
This demo utilizes the Twilio Response Library to facilitate TwiML creation. If you haven't already, visit the Response Library introduction to familiarize yourself. Make sure to download a copy of the PHP library.
We first provide a HTML form to the user containing a field for the user's phone number.
CREATE TABLE voicemailbox ( vmb_extension varchar(8) primary key not null, vmb_description varchar(32) not null, vmb_passcode varchar(8) not null, vmb_last_checked datetime ); insert into voicemailbox ( vmb_extension, vmb_description, vmb_passcode )values ( '1234', 'Test voicemail', '9411' ); CREATE TABLE messages ( message_id int not null primary key auto_increment, message_frn_vmb_extension varchar(8) not null, message_date datetime not null, message_from varchar(16), message_audio_url varchar(1024), message_flag int(1) default 0 );
Next we'll need to define our data access functions. We'll need a couple functions here: a function for adding a new voicemail to the messages table, functions for retrieving messages, and a function for updating the voicemail flag (new,saved,deleted).
Next we will define the voice application for leaving a voicemail. It has three parts, one to gather and verify the target mailbox, one to prompt the user to record their message, and one part to save the message in the database. If you wished to integrate leaving a voicemail into another application, you'd redirect the call to leave_a_message.php?exten=[the mailbox extension] rather than asking the caller to provide the mailbox.
<?php
require "Services/Twilio.php";
include "messages.php";
$error = false;
//if we received an extension, attempt to look it up from the voicemailbox table
if (strlen($_REQUEST['Digits'])) {
$exten = $_REQUEST['Digits'];
//if the mailbox exists, redirect the call to the leave_a_message.php
if (getMailbox($exten)) {
header("location: leave_a_message.php?exten=$exten");
exit();
} else {
$error=true;
}
}
$response = new Services_Twilio_Twiml();
$gather = $response->gather();
if($error)
$gather->say("Mailbox for extension $exten was not found");
$gather->say("Enter the extension you wish to leave a message for, followed by"
. " the #sign");
$response->say('I did not receive an extension.');
$response->redirect('pick_mailbox.php');
print $response;
?>
Prompt the caller to leave a message and record them.
Save the message they left into the database
That's it! If you point your Twilio incoming phone number at pick_mailbox.php and call it, you will be prompted to pick a mailbox, prompted to leave a message, and the message will be saved and flagged as new.
Next lets define the php application that handles the phone call. Here we use the Twilio Response Library to facilitate TwiML creation. We no longer have to mix PHP and XML, keep the code clean and understandable. If you haven't already, visit the Response Library introduction to familiarize yourself.
<?php
require "Services/Twilio.php";
require "messages.php";
$error=false;
if (strlen($_REQUEST['Digits'])) {
$exten = $_REQUEST['Digits'];
$mailbox = getMailbox($exten);
if ($mailbox===false) {
$error=true;
}else {
header("location: get_passcode.php?exten=$exten");
exit();
}
}
$response = new Services_Twilio_Twiml();
if ($error) {
$response->say('Mailbox not found');
} else {
$response->gather()
->say('Enter your mailbox extension and press the pound key');
}
print $response;
?>
Once we have the mailbox, ask for the passcode. Look up the passcode for the mailbox and compare it to what the caller entered. If they match, move on the message_menu.php
<?php
require "Services/Twilio.php";
include "messages.php";
if(strlen($_REQUEST['exten'])){
$exten=$_REQUEST['exten'];
} else {
$response = new Services_Twilio_Twiml();
$response->say("An error occured in the voicemail system");
die((string) $response);
}
if(strlen($_REQUEST['Digits'])){
$code = $_REQUEST['Digits'];
$mailbox = getMailbox($exten);
if($mailbox['passcode']!=$code) {
$error=true;
} else {
header("location: message_menu.php?exten=$exten");
exit();
}
}
$response = new Services_Twilio_Twiml();
if ($error) {
$response->say('Passcode incorrect, please try again');
} else {
$response->gather()
->say("Enter the passcode for mailbox $exten");
}
print $response;
?>
Listen.php is passed an array of message ids and a starting point. As a caller listens to messages, he can interrupt the message with instructions like skip, save, or delete. If they hit 2 or 3, the code updates the message record, marking it saved or deleted. Each time the Gather is submitted or the Redirect is hit, the current message is incremented so you hear the next message.
<?php
require "Services/Twilio.php";
include "messages.php";
$first = true;
if (strlen($_REQUEST['exten'])) {
$exten=$_REQUEST['exten'];
} else {
$response = new Services_Twilio_Twiml();
$response->say("An error occured in the voicemail system");
die((string) $response);
}
$messages = array();
$total_messages = 0;
if (strlen($_REQUEST['messages'])) {
$msg_list = $_REQUEST['messages'];
$messages = preg_split("/,/",$_REQUEST['messages']);
$total_messages = count($messages);
}
$current_msg = 0;
if (strlen($_REQUEST['current_msg'])) {
$current_msg = $_REQUEST['current_msg'];
$first = false;
}
if (strlen($_REQUEST['Digits'])) {
$digits = $_REQUEST['Digits'];
if($digits == 1){
//skip
} else if ($digits == 2){
//save
updateMessageFlag($messages[$current_msg],1);
} else if ($digits == 3){
//delete
updateMessageFlag($messages[$current_msg],2);
}
if($current_msg + 1 < $total_messages) {
$current_msg++;
} else {
$response = new Services_Twilio_Twiml();
$response->say("There are no more messages");
$response->say("Main menu");
$response->redirect("get_mailbox.php");
print $response;
exit();
}
}
$flag = 0;
if (strlen($_REQUEST['flag'])) {
$flag = $_REQUEST['flag'];
}
$msg = getMessage($messages[$current_msg]);
$url = $msg['url'];
$from = $msg['from'];
$date = $msg['date'];
$msg_list = urlencode($msg_list);
$response = new Services_Twilio_Twiml();
$gather = $response->gather(
array(
"action" => "listen.php?exten=$exten&messages=$msg_list"
. "¤t_msg=$current_msg",
"numDigits" => "1",
"timeout" => "5",
)
);
if($first) {
$gather->say("Press 1 to skip, 2 to save, 3 to delete");
} else {
$gather->say("Next Message");
}
$message = "Message from $from received on "
. date('l jS \of F Y h:i A', strtotime($date));
$gather->say($message);
$gather->play($url);
$gather->redirect("listen.php?exten=$exten&messages=$msg_list"
. "¤t_msg=$current_msg&Digits=1");
print $response;
?>
There are many, many ways to extend and improve on this example. You could add a hook to the handle_message.php file, having it email the audio URL when a message is saved. You could build a web interface using the data access functions in messages.php which would let you check and manage your voicemail in a web browser rather than over the phone. You can add custom greetings and audio prompts using your own recordings and the Play verb. Experiment!