Girl receiving SMS messages

Send SMS text messages using Go & Twillio

There are a lot of service providers which offer SMS sending capabilities. In this example we’re looking at using Twillio which has been around for a long time and is very established. Besides sending SMS text messages they also support voice and fax services and the ability to send push notifications to a mobile application. Sign up for a free Twillio account and register a phone number. They have numbers for many geographical locations, so you should be able to find a number local to your business.

The Twillio service provides a simply rest API for sending SMS text messages. In this tutorial we’ll write a Go function which interacts with the API using a web client. You’ll learn how to create a function called sendSMS which accepts two parameters. The first parameter will accept the mobile phone number to send the message too. The second parameter will be the actual message you want to send.

    
func main() {
    err := sendSMS(
        "+447934006066",
        "The application server is down!")

    if err != nil {
        fmt.Println("Couldn't send the text message!")
        fmt.Println(err.Error())
    }
}
    

First you’ll need to create variables for your Twillio account ID and the authentication token which goes with the account. These are obtained from the Twillio web site for your account. The twillioAPI variable will hold the API endpoint that our program will communicate with. This URL is based on your Twillio account.

    
var (
    twillioAccount   = "XXXXXX"
    twillioAuthToken = "YYYYYY"
    twillioAPI       = "https://api.twilio.com/2010-04-01/Accounts/"
                     + twillioAccount + "/Messages.json"
)
    

Let’s start by defining our sendSMS Go function. The function will return any error encountered within it so that the calling block of code can handle the error. As you can see the function accepts two string variables for the mobile number and message. The variable apiValues is used to set the To and Body values passed into the function and we’ve hard coded the mobile number we are sending the message from. This will be the number that you register with Twillio. We then setup a strings Reader called apiValuesReader to read these values and pass them onto the web client.

    
func sendSMS(mobileNumber, message string) error {
    var err error
    var apiValues    url.Values
    var webClient   *http.Client
    var webRequest  *http.Request
    var webResponse *http.Response

    // define a web request to the Twillio API
    // endpoint passing in the prepared values
    apiValues = url.Values{}
    apiValues.Set("To", mobileNumber)
    apiValues.Set("From", "+44122663032")
    apiValues.Set("Body", message)
    apiValuesReader := *strings.NewReader(apiValues.Encode())
}
    

The next step within the process is to create a webRequest object which uses the HTTP POST method on the Twillio API endpoint, passing in the values string reader. We need to check if creating this new request produced an error. If it has then we return the err and exit the function. If the request was created successfully, then we can set the HTTP authentication using our Twillio account ID and authentication token. We also need to set the appropriate HTTP headers for Accept and Content-Type

    
// define a web request to the Twillio API
// endpoint passing in the prepared values
webRequest, err = http.NewRequest("POST", twillioAPI, &apiValuesReader)
if err != nil {
    return err
}

// define the HTTP basic authentication values
// and set two HTTP headers for Accept & Content Type
webRequest.SetBasicAuth(twillioAccount, twillioAuthToken)
webRequest.Header.Add("Accept", "application/json")
webRequest.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    

Now that the web request is setup we can now submit the request to the Twillio service. To do this we define a new http.Client object, setting a timeout of ten seconds. We do this to prevent having to wait for the standard Go timeout if the Twillio site is off-line. Again, we check the error status of web client call and return the error if one is encountered.

    
// create a web client with a
// timeout & submit the request
webClient = &http.Client{
    Timeout: 10 * time.Second,
}

webResponse, err = webClient.Do(webRequest)
if err != nil {
    return err
}
    

Finally we check the status code of the web client call to make sure the Twillio API has returned either a 200 or a 300 status code. If it has’nt we create a new error and return the actual status code returned.

If the API returns a valid HTTP status code, then we attempt to parse the returned JSON content. If Twillio successfully sent the SMS message then the returned JSON will contain an attribute called sid which is the messages unique sending ID produced by Twillio. In the example shown below we’re decoding the JSON and printing out this message ID if found within the response.

    
// check the response from the Twillio API
if webResponse.StatusCode >= 200 &&
    webResponse.StatusCode < 300 {

    // parse the returned data
    // & display the message ID
    var responseData map[string]interface{}
    decoder := json.NewDecoder(webResponse.Body)
    err := decoder.Decode(&responseData)
    if err == nil {
        fmt.Println("Message sent with ID")
        fmt.Println(responseData["sid"])
        return nil
    }
    return err
}

return errors.New(webResponse.Status)
    

The complete code

    
package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "net/http"
    "net/url"
    "strings"
    "time"
)

var (
    twillioAccount   = "XXXXX"
    twillioAuthToken = "YYYYY"
    twillioAPI       = "https://api.twilio.com/2010-04-01/Accounts/"
                      + twillioAccount + "/Messages.json"
)

func main() {
    err := sendSMS(
        "+447934006066",
        "The application server is down!")

    if err != nil {
        fmt.Println("Couldn't send the text message!")
        fmt.Println(err.Error())
    }
}

func sendSMS(mobileNumber, message string) error {
    var err error
    var apiValues url.Values
    var webClient *http.Client
    var webRequest *http.Request
    var webResponse *http.Response

    apiValues = url.Values{}
    apiValues.Set("To", mobileNumber)
    apiValues.Set("From", "+441228830322")
    apiValues.Set("Body", message)
    apiValuesReader := *strings.NewReader(apiValues.Encode())

    webRequest, err = http.NewRequest("POST", twillioAPI, &apiValuesReader)
    if err != nil {
        return err
    }

    webRequest.SetBasicAuth(twillioAccount, twillioAuthToken)
    webRequest.Header.Add("Accept", "application/json")
    webRequest.Header.Add("Content-Type", "application/x-www-form-urlencoded")

    webClient = &http.Client{
        Timeout: 10 * time.Second,
    }

    webResponse, err = webClient.Do(webRequest)
    if err != nil {
        return err
    }

    if webResponse.StatusCode >= 200 &&
        webResponse.StatusCode < 300 {

        var responseData map[string]interface{}
        decoder := json.NewDecoder(webResponse.Body)
        err := decoder.Decode(&responseData)
        if err == nil {
            fmt.Println("Message sent with ID")
            fmt.Println(responseData["sid"])
            return nil
        }
        return err
    }
    return errors.New(webResponse.Status)
}
    

I hope you found this article useful, you can discuss it on Twitter
I create educational content for developers, hoping to inspire and teach with a deep understanding.

Paul Bradley