Sending SMS with Julia and Twilio

July 09, 2021
Written by
Reviewed by

Sending SMS with Julia and Twilio

First released in 2012, Julia is a programming language designed mainly for numerical and scientific computing, including machine-learning and distributed computing. However, it is also perfectly capable as a general-purpose programming language and has several interesting features..

In this post I'll give you a gentle introduction to Julia, introduce a few things which I think make the language interesting, and finish by building up a short script that calls the Twilio API to send an SMS.

Getting started with Julia

For this post we will be working on the command line, so you need to get to the point where you can run the command below

$ julia --version
julia version 1.6.1

To do that, download a version of Julia suitable for your OS and install it, or install Julia using your OS's package manager.

Next, create a new directory called MyFirstJulia and change into it, by running the commands below.

mkdir MyFirstJulia
cd MyFirstJulia

Then, start the interactive REPL by running julia. When Julia starts, you'll see output similar to the following in your terminal.

The Julia REPL.

Here you can try out Julia and see how the language feels. The first few things I always want to know when looking at a new language are:

  • what is the basic syntax, for example adding numbers, concatenating strings, loops and conditionals?
  • how do I define and call functions?
  • what do errors look like?
  • how does the language represent data?
  • What are the most basic built-in types?

If you've used a language like Python or JavaScript you should find Julia's syntax feels quite natural. Julia's documentation is an excellent starting point to find more details.

Here's a quick example:

julia> x = 10
10

julia> y = x+x
20

julia> z = 2x
20

When figuring something out, it's often beneficial to pay close attention to things that evoke surprise. It's easy to dislike things you aren't expecting. However, suspending judgement and digging into those things helps you understand more about how what you're learning is different to things you already know.

This is a great way to use the act of learning a new language to teach you about the fundamentals of programming and is a pretty handy approach to learning in general.

Of course what surprises you depends on your experience, but we've already seen something above which surprised me:  z = 2x. In maths this is a pretty normal expression, but most programming languages don't support this syntax. I found a few more cases where the syntax is designed to read like a mathematical expression - a nod toward Julia's heritage as a programming language for scientific computation. Interesting stuff.

I won't cover much more of Julia's syntax here as the Getting Started guide does that very well indeed. Plus, we will see more of it in context later on. That said, I will just mention a few more things that surprised me.

  • Indices are 1-based. So ["one", "two", "three"][1] is "one" and trying to access the zeroth element of an array or string throws an error.
  • * is used for string concatenation, so "Hello " * "world" == "Hello world"
  • Functions can be declared in a way that looks like mathematical expressions, eg: f(x,y) = x+y.
  • There's a neat way to return multiple values from a function. The function below returns a tuple which is then destructured - it sounds complicated but the syntax is very light:
julia> sumAndProduct(x,y) = x+y, x*y
sumAndProduct (generic function with 1 method)

julia> a,b = sumAndProduct(2,3)
(5, 6)
  • "Backwards" division is possible: 2\3 == 3/2
  • Complex and rational numbers (fractions) are supported in Julia. The syntax for a rational number uses //, so 4//6 is two-thirds as an exact value (not a decimal or binary approximation).
  • Operators can be used as functions: +(2,3,4) == 2 + 3 + 4.
  • There are version-number literals, so that v"2.10" > v"2.9". This is really handy because normal string sorting puts 2.10 before 2.9.

Two more things stood out to me:

  1. Excellent inline help at the REPL. Type ? to go into help mode, then the name of the thing you want to know about:
Julia inline help.
  • The error messages are extremely helpful, with human-readable explanations and suggestions:
An example of a Julia error message

There is a lot more to consider when learning a new language: How to handle errors? What is included in the standard library? How to write asynchronous code? How is data managed in multi-threaded code? What are the polymorphism options? How are large codebases organised? What are the variable scope rules? Is metaprogramming supported? How do I write tests? How can I import dependencies? What are the build tools like? What is the community like?

The list is long and the above is not at all exhaustive. However, again, Julia's documentation is excellent and I found the online community discussions to be helpful, polite and respectful.

Hopefully what you've seen so far gives you a taste of Julia, and the means to find out more. I liked it a lot, and couldn't wait to write a real program with it.

The program I chose is to call the Twilio API to send an SMS, which will exercise the basics of the language as well as making HTTP requests and parsing JSON. I find these tasks so common that I won't enjoy using a language which makes them difficult.

Sending an SMS using the Twilio API

The code for sending an SMS using the Twilio API will need to make an HTTP request and parse the JSON response. To do this, you will need the following two things:

  • A Twilio account (sign up using this link to get $10 credit when you upgrade).
  • A Twilio phone number. You can get one using the Twilio console or CLI.

Install the required dependencies

You can install dependencies into Julia's default project, which makes them available system-wide. This is an easy way to get started, although later on you might want to create project-specific environments. Julia has a package manager called Pkg which has an interactive mode available from the REPL. Enter it by typing ] and add the dependencies with:

add JSON
add HTTP

There is a lot of output from those two commands, which I haven't shown. When they're finished, the dependencies will be installed in ~/.julia. With the dependencies installed, exit Pkg with Ctrl-c or backspace, and exit the REPL with Ctrl-d or exit().

From now on, we'll be writing our source code in a file and running it from the command line. For editing the code, any text editor will do. I found julia-mode for emacs did the job well. If you're a VS Code fan the support looks excellent.

Setting up your Twilio credentials

You will need to use your Twilio Account SID and Auth Token in code, but you should never hard-code these values. Instead we recommend setting them as environment variables. You can find the values on your Twilio Console and set them in your environment with

export TWILIO_ACCOUNT_SID=ACxxxxxxxxxx
export TWILIO_AUTH_TOKEN=xxxxxxxx

Julia lets you read these in your code with a global Dict called ENV.

Writing the code

Create a file called SendSms.jl and put the content below into it. I've put comments on lines which show interesting features of Julia:

using HTTP
using JSON


# Use a ; to separate positional and named arguments
# Here, we only have named args
function send_sms(;message, from, to)

        account_sid = ENV["TWILIO_ACCOUNT_SID"]
        auth_token  = ENV["TWILIO_AUTH_TOKEN"]

        # Note: String interpolation
        endpoint = "api.twilio.com/2010-04-01/Accounts/$account_sid/Messages.json"
        url = "https://$account_sid:$auth_token@$endpoint"

        # This is a nice function:
        #   help?> HTTP.URIs.escapeuri
        #        escapeuri(query_vals)
        #        Percent-encode and concatenate a value pair(s) as they would conventionally
        #        be encoded within the query part of a URI.
        request_body = HTTP.URIs.escapeuri([:From => from, :To => to, :Body => message])

        request_headers = ["Content-Type" => "application/x-www-form-urlencoded"]

        try
            response = HTTP.post(url, request_headers, request_body)
            return JSON.parse(String(response.body))
            
        catch e
            
            if e isa HTTP.ExceptionRequest.StatusError
                # response status was 4xx or 5xx
                # throw an error with the body of the API response
                error(JSON.parse(String(e.response.body))["message"])
                
            else
                # Some other kind of error, which we can't handle
                rethrow()

            end # if

        end # try/catch

end # function

result = send_sms(message="Hello from Twilio! ☎", from="<YOUR_TWILIO_NUMBER>", to="<YOUR_REAL_NUMBER>")
println(result["sid"])

[this code on GitHub]

To send your first SMS from Julia, first fill in the real values for <YOUR_TWILIO_NUMBER> and <YOUR_REAL_NUMBER> (using E.164 format) on line 46, then send an SMS by running the command below.

julia SendSms.jl

Congratulations! You've just sent your first SMS using Julia.

The first SMS sent using Julia

Summing up

If this was your first time looking at Julia, what did you think? Personally, I found it really interesting, with a few features I hadn't seen before. There is a lot more to it and I can't wait to build something bigger and try out some of the more advanced features of the language. Things like macros, and asynchronous and distributed programming really excite the language nerd in me.

If you're building with Julia and Twilio, or would like to share any cool programming languages with me, get in touch. I can't wait to see what you build!