Send SMS and MMS Messages In C++

January 12, 2017
Written by
Paul Kamp
Twilion
Reviewed by
Kat King
Twilion
Maylon Pedroso
Contributor
Opinions expressed by Twilio contributors are their own

cpp-sms

Today we'll use C++, some standard libraries, libcurl, and some POSIX APIs to send SMS and MMS messages using the Twilio REST API.  You'll need a (mostly) POSIX-compliant build environment as well as libcurl to follow along with this guide.

Let's get started!

Sign Up for (or Sign In to) a Twilio Account

You'll need to login to your existing Twilio account, or create a new account.

Don't have an account yet?  Sign up for a free Twilio trial, post-haste.

Purchase or Find a SMS-Capable Number

You'll need a SMS (or optionally, MMS) capable number to complete this demo.  Either use a phone number that you already have, or purchase a new one with SMSes enabled.  

From the Twilio Console, here's where you can determine the capabilities of your purchased number:

 

Active Numbers List

 

If you need to purchase a number, after navigating to the 'Buy a Number' link click the SMS checkbox (and the MMS checkbox, if you wish to send media messages).

Buy A Number

 

Prerequisites for This C++ MMS and SMS Guide

We're targeting POSIX Compliant environments with this guide, and tested our code with clang-800.0.42.1 on Mac OSX 10.11, gcc version 4.9.2 on Raspbian 8.0 (kernel 4.4.38-v7+) and gcc 5.4.0 in Cygwin 2.877 on Windows 7 64-Bit.  

To build, you will need to ensure you have:

libcurl was already on the Mac.  On the Raspberry Pi, you can install a suitable version with:

sudo apt-get install libcurl4-openssl-dev

In Windows 7 and Cygwin, you can install libcurl with Cygwin Setup:

Installing libcurl-devel and curl in Cygwin

Building cpp_demo

All three environments worked with this example Makefile.  You may need to make minor edits - usually to the library search paths - to build in your environment.

On almost all *NIX-type systems (including Windows/Cygwin), building should be very similar to the following lines (you might even be able to copy, paste and execute):

git clone https://github.com/TwilioDevEd/twilio_cpp_demo.git
cd twilio_cpp_demo
make

Send an SMS or MMS Message with C++

We've just built cpp_demo, which attempts to send an SMS or MMS based on your inputs from the command line.  src/twilio.cc and include/twilio.hh demonstrate a class, Twilio, which should be easy to integrate into your own codebase.  (Note that before putting it into production, you need to add input validation and safety.  The first order of concern: the code in its current form can be passed additional HTTP parameters through the command line inputs.)

For C++ developers, our C SMS and MMS guide might give some key insights into the following code - but let's take a closer look to see what's happening under the hood.

  • First, we instantiate a Twilio object with our account credentials (find them on the Twilio Console).
  • Second, we call the method send_message with the to/from numbers, the message, and optionally a URL to a picture and a boolean of whether we want verbose output.

This is a migrated tutorial. Clone the original code from https://github.com/TwilioDevEd/twilio_cpp_demo/

/*
* This example demonstrates sending a SMS or MMS in C++ using the Twilio REST
* APIs.  After building, you should be able to run it with:
* 
* ./bin/cpp_demo
* 
*/

#include <iostream>
#include <string>
#include <memory>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "twilio.hh"


int main(int argc, char * argv[])
{
        int cmd;
        std::string account_sid;
        std::string auth_token;
        std::string message;
        std::string from_number;
        std::string to_number;
        std::string picture_url;
        bool verbose = false;

        opterr = 0;

        while ((cmd = getopt(argc, argv, "a:s:m:f:t:p:vh?")) != -1) {
                switch (cmd) {
                        case '?':
                        case 'h':
                                printf("Twilio C++ Example Help:\n");
                                printf("-a: Account\t\t"
                                       "(ex: -a \"ACXXXXX\")\n");
                                printf("-s: Auth Token\t\t"
                                       "(ex: -s \"your_token\")\n");
                                printf("-f: From Number\t\t"
                                       "(ex: -f \"+18005551212\")\n");
                                printf("-t: To Number\t\t"
                                       "(ex: -t \"+18005551212\")\n");
                                printf("-m: Message to send\t"
                                       "(ex: -m \"Hello, Twilio!\")\n");
                                printf("-p: (Opt.) URL to Image\t"
                                       "(ex: -p \"Hello, Twilio!\")\n");
                                printf("-v: Verbose Mode\n");
                                printf("-h: This help dialog\n");
                                return 0;
                        case 'a':
                                account_sid = optarg;
                                break;
                        case 's':
                                auth_token = optarg;
                                break;
                        case 'm':
                                message = optarg;
                                break;
                        case 'f':
                                from_number = optarg;
                                break;
                        case 't':
                                to_number = optarg;
                                break;
                        case 'p':
                                picture_url = optarg;
                                break;
                        case 'v':
                                verbose = true;
                                break;
                        default:
                                abort();
                }
        }

        if ( account_sid.empty() or auth_token.empty() or from_number.empty()
                or to_number.empty() or message.empty() ) {
                std::cout<< "You didn't include all necessary inputs!\n"
                        "Call using -h for help.\n" << std::endl;
                return -1;
        }

        // Instantiate a twilio object and call send_message
        std::string response;
        auto twilio = std::make_shared<twilio::Twilio>(
            account_sid, 
            auth_token
        );
        
        bool message_success = twilio->send_message(
                to_number, 
                from_number, 
                message,
                response,
                picture_url,
                verbose
        );

        // Report success or failure
        if (!message_success) {
                if (verbose) {
                        std::cout << "Message send failed." << std::endl;
                        if (!response.empty()) {
                                std::cout << "Response:" << std::endl 
                                        << response << std::endl;
                        }
                }
                return -1;
        } else if (verbose) {
                std::cout << "SMS sent successfully!" << std::endl;
                std::cout << "Response:" << std::endl << response
                        << std::endl;
        }

        return 0;
}
  • Third, once inside the code we first do some exception checking (making sure the message is the proper size), followed by setting up libcurl with our eventual HTTP POST
  • Fourth, curl makes the HTTP POST and we clean up with curl_easy_cleanup.
  • Finally, we check the response for success or failure, and return the result to the calling function.
#include <sstream>
#include <curl/curl.h>

#include "twilio.hh"


namespace twilio {

Twilio::Twilio(
        const std::string& accound_sid_in, 
        const std::string& auth_token_in
)
{
    account_sid = accound_sid_in;
    auth_token = auth_token_in;
}

void Twilio::set_account_sid(const std::string& accound_sid_in)
{
        account_sid = accound_sid_in;
}

void Twilio::set_auth_token(const std::string& auth_token_in)
{
        auth_token = auth_token_in;
}

// Portably ignore curl response
size_t Twilio::_null_write(
        char *ptr, 
        size_t size, 
        size_t nmemb, 
        void *userdata)
{
        return size*nmemb;
}

// Write curl response to a stringstream
size_t Twilio::_stream_write(
        char *ptr,
        size_t size,
        size_t nmemb,
        void *userdata) 
{
        size_t response_size = size * nmemb;
        std::stringstream *ss = (std::stringstream*)userdata;
        ss->write(ptr, response_size);
        return response_size;
}

// Method send_message:
//   Returns 'true' if the result of the eventual HTTP post to Twilio is status
//   code 200 or 201.  Either other status codes or errors in curl will cause
//   a false result.
//   Inputs:
//        - to_number: Where to send the MMS or SMS
//        - from_number: Number in your Twilio account to use as a sender.
//        - message_body: (Max: 1600 characters) The body of the MMS or SMS 
//                message which will be sent to the to_number.
//
//   Outputs:
//        - response: Either the curl error message or the Twilio response
//                if verbose.
//   Optional:
//        - picture_url: If picture URL is included, a MMS will be sent
//        - verbose: Whether to print all the responses
bool Twilio::send_message(
        const std::string& to_number,
        const std::string& from_number,
        const std::string& message_body,
        std::string& response,
        const std::string& picture_url,
        bool verbose)
{
        std::stringstream response_stream;

        // See: https://www.twilio.com/docs/api/rest/sending-messages for
        // information on Twilio body size limits.
        if (message_body.length() > 1600) {
                response_stream << "Message body must have 1600 or fewer"
                        << " characters. Cannot send message with "
                        << message_body.length() << " characters.";
                response = response_stream.str();
                return false;
        }

        CURL *curl;
        curl_global_init(CURL_GLOBAL_ALL);
        curl = curl_easy_init();
        


        std::stringstream url;
        std::string url_string;
        url << "https://api.twilio.com/2010-04-01/Accounts/" << account_sid
                << "/Messages";
        url_string = url.str();


        std::stringstream parameters;
        std::string parameter_string;
        parameters << "To=" << to_number << "&From=" << from_number 
                << "&Body=" << message_body;
        if (!picture_url.empty()) {
                parameters << "&MediaUrl=" << picture_url;
        }
        parameter_string = parameters.str();


        curl_easy_setopt(curl, CURLOPT_POST, 1);
        curl_easy_setopt(curl, CURLOPT_URL, url_string.c_str());
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, parameter_string.c_str());
        curl_easy_setopt(curl, CURLOPT_USERNAME, account_sid.c_str());
        curl_easy_setopt(curl, CURLOPT_PASSWORD, auth_token.c_str());
        if (!verbose) {
                curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _null_write);
        } else {
                curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _stream_write);
                curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_stream);
        }


        CURLcode res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
        long http_code = 0;
        curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code);

        // Check for curl errors and Twilio failure status codes.
        if (res != CURLE_OK) {
                response = curl_easy_strerror(res);
                return false;
        } else if (http_code != 200 && http_code != 201) {
                response = response_stream.str();
                return false;
        } else {
                response = response_stream.str();
                return true;
        }
}

} // end namespace twilio

Running cpp_demo

Running cpp_demo from the command line is easy once you have it built.  Merely set your account credentials and call the code as follows:

account_sid=ACXXXXXXXXXXXXXXXXXXXXXX
auth_token=your_auth_token
bin/cpp_demo -a $account_sid -s $auth_token -t "+18005551212" -f "+18005551213" -m "Hello, World!"
# Optionally, use '-p http://some/path/to/img.jpg' to send an MMS.

Getting C-Rious With Twilio and C++

After this demo, you now have the means to add communications to your new or existing C++ applications.  Add monitoring or help to your C++ application, or bring your own use case.

Whether you're a C++ pro or closer to a practitioner of "C with classes" please do let us know on Twitter when you've got something built!