So It Goes: Sending SMS with Golang

September 25, 2017
Written by
Alaina Kafkes
Contributor
Opinions expressed by Twilio contributors are their own

Vonnegut books

Whether stored on your phone, on Post-It notes, or in a book, everyone has their share of quotes that they look at to seek inspiration. Personally, I follow @Kurt Vonnegut. No, not the real (dead) Vonnegut: just a human or bot that tweets out some of his famous quips.

Remembering Vonnegut, an idea struck: what better way get started with Twilio than to send Vonnegut quotes to all of your friends? That’s exactly what this blog post goes over: how to send SMS text messages with Vonnegut quotes in Golang.

Let’s Go: Developer Environment Setup

Before we can get coding, take a moment to install Golang on your computer. Follow the instructions for your operating system, and feel free to test your installation locally.

If you’ve never seen Golang code before, I recommend that you poke around the Golang Tour. If you really want to dig deeper, the Golang Docs will be your best friend.

If you tested your Golang installation locally, you probably created a Golang program (main.go) that looks something like this:

package main

import (
  // packages will go here!
)

func main() {
  // code will go here!
}

The Golang program we’ll be working with today will have this basic code skeleton. Each Golang program starts running in a package called main. Writing package main at the top of your program specifies to the compiler that the program you are writing should compile, running successfully.

While in main, the program may import other packages that expand upon the functionality provided by the package main. These other packages will be found in import statement(s).

Similar to C++, there is a function called main whose code gets executed. Other functions can be created within this Golang program, but they will not be executed unless called in main.

You can execute any Golang program by opening up the command line, navigating to the directory where your program lies, and typing in the command go run main.go.

Again, if you’d like to get more comfortable with the syntax, check out the Golang Tour. Now let’s move on to writing some Golang code that will enable our program to pick Vonnegut quotes at random from an array for our future SMS message.

Randomly Generating Quotes with Golang

Spoiler alert: what we’re about to do may sound straightforward, but really tripped me up. Even if you’re great at writing random item generators in other languages, you don’t want to skip this section.

Start with a program called main.go if you didn’t already create it in the last section. It should have the Golang skeleton code mentioned previously:

package main

import (
  // packages will go here!
)

func main() {
  // code will go here!
}

Import a package called math/rand, which will allow us to implement a random number generator. math/rand is deterministic, which means that any random number generator created with it will produce the same output given the same starting state. In other words, if you run the following code a few times, you should see the same number – some integer between 0 and 10 – printed over and over again due to rand.Intn.

package main

import (
  "fmt"
  "math/rand"
)

func main() {
  fmt.Println(rand.Intn(10))
}

But what if we want a different random number to be generated each time? How do we circumvent the deterministic nature of math/rand? Based on the aforementioned definition of deterministic, all that needs to be done is change the starting state each time the program is executed.

The most common way to do this is to use rand.Seed to set this starting state to the current Unix time. Why? Given there will be at least one second between each execution of main.go, the starting state will be a different Unix time on each run, which means the random integer produced by rand.Intn will be truly random.

package main

import (
  “fmt”
  “time”
  “math/rand”
)

func main() {
  rand.Seed(time.Now().Unix())
  fmt.Println(rand.Intn(10))
}

Now that we’ve built our random number generator, let’s use it to select a random quote from an array of Kurt Vonnegut quotes. In the code snippet below, there is now an array with seven Vonnegut quotes to main(), as well as the  print statement fmt.Println so that it prints the Vonnegut quote at the array index given by the randomly generated number.

package main

import (
  "fmt"
  "time"
  "math/rand"
)

func main() {

  quotes := [7]string{"I urge you to please notice when you are happy, and exclaim or murmur or think at some point, 'If this isn't nice, I don't know what is.'",
                      "Peculiar travel suggestions are dancing lessons from God.",
                      "There's only one rule that I know of, babies—God damn it, you've got to be kind.",
                      "Many people need desperately to receive this message: 'I feel and think much as you do, care about many of the things you care about, although most people do not care about them. You are not alone.'",
                      "That is my principal objection to life, I think: It's too easy, when alive, to make perfectly horrible mistakes.",
                      "So it goes.",
                      "We must be careful about what we pretend to be."}

  rand.Seed(time.Now().Unix())
  fmt.Println(quotes[rand.Intn(len(quotes))])
}

Run this program a few times and you should see a few different Kurt Vonnegut quotes from this array printed.

Say Hello to Twilio

If you’ve used Twilio before, feel free to say goodbye to this section. :)

Navigate to the Twilio sign-up page to sign up for Twilio for free. Where prompted, note that you’d like to develop an app with SMS capabilities.

Upon filling out account details, you’ll be brought to the trial account page, which shows that you have $15.50 to make calls, send SMS, et cetera using Twilio. Given Twilio’s generous SMS pricing model, you won’t have to worry about blowing all of your trial money in this tutorial.

After pressing the Get Started button, get a fancy Twilio phone number.

Try sending an initial message to your phone with the Twilio Send a Message tool that pops up. If it works, then we’re good to go back to Golang.

Sending SMS Programmatically with Golang

On to the most fun part – using Golang to send SMS messages via Twilio!

Let’s start out with this starter code, which is a slight extension on what we built in previous sections.

Fill in the accountSid and authToken variables with your unique Account SID and Auth Token, both of which can be found on the Twilio Console.

package main

import (
  "fmt"
  "math/rand"
  "time"
)

func main() {
  // Set account keys & information
  accountSid := "ACXXXX"
  authToken := "XXXXXX"
  urlStr := "https://api.twilio.com/2010-04-01/Accounts/"   accountSid   "/Messages.json"

  // Create possible message bodies
  quotes := [7]string{"I urge you to please notice when you are happy, and exclaim or murmur or think at some point, 'If this isn't nice, I don't know what is.'",
                      "Peculiar travel suggestions are dancing lessons from God.",
                      "There's only one rule that I know of, babies—God damn it, you've got to be kind.",
                      "Many people need desperately to receive this message: 'I feel and think much as you do, care about many of the things you care about, although most people do not care about them. You are not alone.'",
                      "That is my principal objection to life, I think: It's too easy, when alive, to make perfectly horrible mistakes.",
                      "So it goes.",
                      "We must be careful about what we pretend to be."}

  // Set up rand
  rand.Seed(time.Now().Unix())

After setting up our future random number generator to be non-deterministic, there are three additional features to add to this program:

  • Specify the SMS data (sender, receiver, message body)
  • Create an HTTP request client
  • Make HTTP POST request with HTTP client

Create and pack up the SMS message to be sent. Replace NUMBER_FROM with the sender’s phone number (your Twilio phone number) and NUMBER_TO with the receiver’s phone number. Make sure to format these phone numbers like ‘+1234567890’. The net/url and strings packages must also be added to the import statement for this code snippet to compile.

msgData := url.Values{}
msgData.Set("To","NUMBER_TO")
msgData.Set("From","NUMBER_FROM")
msgData.Set("Body",quotes[rand.Intn(len(quotes))])
msgDataReader := *strings.NewReader(msgData.Encode())

In this code block, url.Values{} is created to store and encode the URL parameters – sender (“From”), receiver (“To”), and message body (“Body”) – and the Reader created allows this object to be parsed like a string.

Next, we’re going to set up an HTTP client and an HTTP POST request. The variable req holds that request, and to it we give our Twilio credentials with req.SetBasicAuth() and add headers to the request with req.Header.Add. The net/http package must be added to the import statement for this code snippet to compile.

client := &http.Client{}
req, _ := http.NewRequest("POST", urlStr, &msgDataReader)
req.SetBasicAuth(accountSid, authToken)
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

Though the HTTP client client and HTTP POST request req have been created, they are not used in this code snippet.

Finally, we’re going to use the HTTP request client to make a POST request. We will make the HTTP POST request req using the HTTP client client, and store the result in the variable resp.  The encoding/json package must be added to the import statement for this code snippet to compile.

resp, _ := client.Do(req)
if (resp.StatusCode >= 200 && resp.StatusCode < 300) {
  var data map[string]interface{}
  decoder := json.NewDecoder(resp.Body)
  err := decoder.Decode(&data)
  if (err == nil) {
    fmt.Println(data["sid"])
  }
} else {
  fmt.Println(resp.Status);
}

You may be wondering why the outermost if statement checks if resp.StatusCode is between 200 and 300. This is because an HTTP status code with the form 2XX signifies a successful HTTP POST request. Then, we can use json.NewDecoder to read the response’s body and see if any errors occurred.

If the HTTP POST request is a success and the innermost if statement shows that there is no error, the SMS message SID will be printed to your command line. This means you have successfully sent an SMS message via Twilio. Yay!

But what if you don’t see the SMS message SID? If the HTTP status code did not fall within the 200s, the else statement will print information about why the HTTP POST request failed on the command line. You can check out what other HTTP status codes mean here, and troubleshoot from there.

Did You Get My Text?

Before I reveal the final code, take a look at your import statement. Does it look something like this?

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

If so, you followed along with the last section swimmingly! High five. If you seem to be missing a package or two, scroll back up to the Sending SMS Programmatically with Golang section of this tutorial and see what you missed.

Drumroll, please… take a peek at the final code to see how you did. If you’re feeling confident, type go run main.go into your command line prompt, and that SMS will send! 


You can confirm that your message sent by navigating to Twilio’s Programmable SMS Dashboard and looking under Recent Messages.

Conclusion

Hope you enjoyed this Twilio and Golang mashup with a hint of Vonnegut. Feel free to get creative and customize those quotes, or even work on more complex Twilio projects with Golang.

Thank you to developer evangelists Matt Makai and Lizzie Siegle for revising and helping me publish my work via Twilio Voices. If you have any questions or comments, please don’t hesitate to reach out to me on Twitter, GitHub or email!