Sending SMS

Being able to send SMS text messages to our users is another way for us to connect with them

It is possible to connect our computer to a GSM modem, interact with specialized libraries (such as Asterisk, asterisk.org, combined with ngSMS, ozekisms.com), and interface with the libraries and the telephony equipment to send SMS messages.

There are easier ways though. Services like Twilio provide gateway SMS services, where we contact them via an HTTP REST API and they handle the SMS sending for us.

In this recipe, we'll convert our newsletter mail out app into a blanket SMS service using the twilio module.

Getting ready

This requires a Twilio account (https://www.twilio.com/try-twilio). Once signed up and logged in we should take note of our Account SID, Auth Token, and Sandbox phone number (we may have to select our country of residence to obtain the appropriate Sandbox number).

We'll need some phone numbers to send texts to for testing purposes. In the sandbox mode (which is what we'll be using for development), any number we want to text or call must go through a verification process. We do this by selecting the Numbers link from the Account section, and clicking Verify a Number. Twilio will then call that number and expect a PIN provided on screen to be entered for confirmation.

Let's create a new file, smsout.js, and install the twilio helper module:

npm install twilio

How to do it...

First, we require twilio and put together some configuration settings:

var twilio = require('twilio'),
var settings =  {
  sid : 'Ad054bz5be4se5dd211295c38446da2ffd',
  token: '3e0345293rhebt45r6erta89xc89v103',
  hostname : 'dummyhost',
  phonenumber: '+14155992671' //sandbox number
}

Tip

Twilio phone number

Before we can start interacting with the Twilio service, we have to specify a registered Twilio phone number in order to create our phone. For development purposes, we can simply use the sandbox number, which can be found from the Twilio dashboard (http://www.twilio.com/user/account). In a production scenario, we would need to upgrade our account and purchase a unique phone number from Twilio.

With our settings present and correct we're ready to create a Twilio client, using it to initialize a virtual phone:

var restClient = new (twilio.RestClient)(settings.sid, settings.token);

var client = new (twilio.Client)(settings.sid,
                                  settings.token,
                                  settings.hostname);


var phone = client.getPhoneNumber(settings.phonenumber);

We created restClient here also, which offers API calls reflective of Twilio's raw REST API. We'll be using restClient to check the status of our SMS message in order to determine if the message has been sent from Twilio to the target phone.

Now we define a list of numbers to text (we'll have to provide our own) to text, much like our maillist array in the previous recipe:

var smslist = [
  '+44770xxxxxx1',
  '+44770xxxxxx2',
  '+44770xxxxxx3',  
  '+44770xxxxxx4',  
  '+44770xxxxxx5'  
];

Tip

Unless we have upgraded our account, any number on smslist must be pre-verified with Twilio. This can be done through the Twilio Numbers account section (https://www.twilio.com/user/account/phone-numbers/).

Then we simply loop through smslist and use phone to send an SMS message to each recipient as follows:

var msg = 'SMS Ahoy!';
smslist.forEach(function (to) {
  phone.sendSms(to, msg, {}, function(sms) { console.log(sms);  });
});

This should work fine, except that the process won't exit (because twilio initializes a server to receive Twilio callbacks) and we don't know when an SMS is actually sent from Twilio to the recipient. One way to check is to make another request to the Twilio REST API asking for a status update. The twilio RestClient makes this easy for us as follows:

  phone.sendSms(to, msg, {}, function(sms) {
      restClient.getSmsInstance(sms.smsDetails.sid, function (presentSms) {
		//process presentSms using it's status property.
      });
  });

If our SMS hasn't been sent on the first call, we need to wait and check it again. Let's make some final improvements as shown in the following code:

var msg = 'SMS Ahoy!',  i = 0;
smslist.forEach(function (to) {
  phone.sendSms(to, msg, {}, function (sms) {
  
  function checkStatus(smsInstance) {  
      restClient.getSmsInstance(smsInstance.sid, function (presentSms) {
       if (presentSms.status === 'sent') {  
          console.log('Sent to ' + presentSms.to);
        } else {
          if (isNaN(presentSms.status)) {
            //retry: if its not a number (like 404, 401), it's not an error
            setTimeout(checkStatus, 1000, presentSms);
            return;
          }
          //it seems to be a number, let's notify, but carry on
          console.log('API error: ', presentSms.message);
        }
        i += 1;
        if (i === smslist.length) { process.exit(); }
      });
    };

    checkStatus(sms.smsDetails);

  });
});

Now the console will output each time a number has been confirmed as sent. When all numbers have been messaged the process exits.

How it works...

The twilio.RestClient gives us access to low-level interactions with the Twitter API via the twilio helper. This simply wraps generic API calls with our preset authorization settings for us, making the HTTP requests on our behalf.

twilio.Client is a higher-level API presented by the twilio helper and handles two-way interactions between Twilio and the client. The third parameter that must be provided to initialize a new client is the hostname parameter. The twilio module provides this to Twilio as part of a callback URL requested from the Twilio servers to confirm that an SMS message has been sent.

We ignored this behavior and supplied a dummy hostname, implementing our own method of confirming an SMS was sent. Our method doesn't require us to have a live server address accessible from the Web (see the There's more... section for a live server implementation that uses the hostname property as intended).

We use the sendSms method of our created phone object to make an HTTP request of the Twilio API via the twilio module, passing in the desired recipient, message, and a callback function.

Once the request is made, our callback is triggered with the initial sms object. We use this to determine the ID that Twilio has given our sendSMS request with smsInstance.sid (which is sms.smsDetails.sid).

smsInstance.sid is passed to restClient.getSmsInstance which provides us with an updated instance of our smsIntance object, we call it presentSms. This call is made from within a custom, self-calling function expression called checkStatus, which has our initial sms.smsDetails object passed to it.

We are looking to see if Twilio has sent our text message yet. If it has, presentSms.status will be sent. If it's anything other than this, we want to wait a short while and then ask Twilio for another update on the status of our queued SMS message. That is, unless the returned status is a 404, in which case there has been an issue and we need to notify the user, but continue on to process the next SMS message.

As in the Sending email recipe, we keep a count of how many messages are sent. Once they total the amount of recipients we exit the process, since smsout.js is a command-line app (in a server scenario we wouldn't need or want to do this).

There's more...

The Twilio module's versatility stretches beyond sending SMS messages. It can also transparently handle Twilio callbacks for us through emitting events.

Using the processed event listener

With a live public server, we would be better off providing our hostname to twilio.Client so it can manage callback URL requests.

Note

For this code to work, it must be hosted on a live public server. For more information on hosting Node on live servers, seeChapter 10,Taking It Live

We would remove restClient and change our settings object to the following:

var settings =  {
  sid : 'Ad054bz5be4se5dd211295c38446da2ffd',
  token: '3e0345293rhebt45r6erta89xc89v103',
  hostname : 'nodecookbook.com',
  phonenumber: '+14155992671' //sandbox number
};

Then our SMS sending code is simply:

var i = 0;
smslist.forEach(function (to) {
  phone.sendSms(to, msg, {}, function(sms) {
    sms.on('processed', function(req) {  
      i += 1;  
      console.log('Message to ' + req.To +
      ' processed with status: ' + req.SmsStatus);
      if (i === smslist.length) {process.exit();}
    });
  });
});

The twilio client provides a statusCallback URL to Twilio. Twilio will request this URL (something like http://nodecookbook.com:31337/autoprovision/0) to confirm and the twilio helper module will emit a processed event to notify us of Twilio's confirmation. We listen out for this event, checking the given SmsStatus via that req object to confirm success.

Making an automated phone call

For this next example to work, we would need to have a valid hostname and be running our app on a web-exposed server as in the previous section.

Note

For this code to work, it must be hosted on a live public server. For more information on hosting Node on live servers, seeChapter 10,Taking It Live

To make a call we start with the usual setup.

var twilio = require('twilio'),

var settings =  {
  sid : 'Ad054bz5be4se5dd211295c38446da2ffd',
  token: '3e0345293rhebt45r6erta89xc89v103',
  hostname : 'nodecookbook.com',
  phonenumber: '+14155992671' //sandbox number
};

var client = new (twilio.Client)(settings.sid,
                                  settings.token,
                                  settings.hostname);


var phone = client.getPhoneNumber(settings.phonenumber);

Then we use the makeCall method as follows:

phone.makeCall('+4477xxxxxxx1', {}, function(call) {
  call.on('answered', function (req, res) {
    console.log('answered'),
    res.append(new (twilio.Twiml).Say('Meet us in the abandoned factory'));
    res.append(new (twilio.Twiml).Say('Come alone', {voice: 'woman'}));
    res.send();
  }).on('ended', function (req) {
    console.log('ended', req);
    process.exit();
  })
});

If our account is not upgraded, whatever number we supply to makeCall must be verified through the Twilio Numbers area in the account section (https://www.twilio.com/user/account/phone-numbers/).

makeCall invokes a callback with a call parameter. call is an event emitter, with answered and ended events. The twilio module transparently converts Twilio confirmation callbacks into these events.

The answered event feeds the req and res objects to its callback. req holds information about the outgoing call, and res has methods which allow us to interact with the call, namely res.append and res.send.

To send a computerized text-to-speech message to the recipient, we instantiate a new instance of the twilio module's Twiml class and use the Say method (watch out for the unusual convention of giving a capital S to a non-class, using a small s will throw an error).

TwiML is Twilio's markup language. It's simply API-specific XML. The twilio module provides the Twiml class to handle the ugly business of forming the necessary XML. We use it to create two Say verbs. Behind the twilio scenes, the two append calls followed by the send invocation would create and issue the following TwiML to twilio:

<?xml version="1.0" encoding="UTF-8" ?>
<Response>
  <Say>
	  Meet us in the abandoned factory
  </Say>
  <Say voice="woman">
	  Come alone
  </Say>
</Response>

The TwiML code is received by twilio and converted into speech. After the woman's voice says Come alone the phone call ends, triggering the ended event in our app (which the twilio module emits as a result of receiving an HTTP request from twilio signifying the call has ended).

We listen to the ended event determining when twilio (or the recipient) have hung up. Once ended has triggered we exit the process, outputting the req object as an overview of the call.

See also

  • Sending email discussed in this chapter
  • Communicating with TCP discussed in this chapter
  • Chapter 10,Taking It Live
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.217.187.19