DEV Community

Kiran Krishnan
Kiran Krishnan

Posted on • Edited on • Originally published at kirandev.com

How to send an SMS with Go using Vonage SMS API

In this article, I'll show you how to send an SMS with Golang using Vonage SMS API

Go to Vonage and create an account to try this code sample.

To send an SMS using Vonage, you must collect the below information from the dashboard

  • API key
  • API secret

vonage-dashboard.png

Create a new folder called send-sms.

mkdir send-sms

cd send-sms

touch main.go
Enter fullscreen mode Exit fullscreen mode

Open the main.go and import the necessary packages.

package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "net/url"
    "strings"
)
Enter fullscreen mode Exit fullscreen mode

Create a struct that models the data received from the API.

type VonageResponse struct {
    Messages []struct {
        Status    string `json:"status"`
        ErrorText string `json:"error-text"`
    } `json:"messages"`
}
Enter fullscreen mode Exit fullscreen mode

To understand the API response, here is an example response returned by Vonage API.

{
  "message-count": "1",
  "messages": [
    {
      "to": "447700900000",
      "message-id": "0A0000000123ABCD1",
      "status": "0",
      "remaining-balance": "3.14159265",
      "message-price": "0.03330000",
      "network": "12345",
      "client-ref": "my-personal-reference",
      "account-ref": "customer1234"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Let's start coding, paste the below code to main.go.

func main() {
    apiKey := "<API Key>"
    apiSecret := "<API Secret>"
    apiPath := "https://rest.nexmo.com/sms/json"

    from := "Vonage APIs"
    to := "<From Number>"

    // This is the message
    message := "Hello Vonage SMS API"
}
Enter fullscreen mode Exit fullscreen mode

Replace the values for apiKey and apiSecret with your own values. Don't forget to change the value for to. It should be the phone number of the receiver.

Now, let's build the request body. Make sure you've the correct values for all the variables.

// Build the request body
body := url.Values{
    "from":         {from},
    "to":           {to},
    "text":         {message},
    "api_key":      {apiKey},
    "api_secret":   {apiSecret},
}

// Create a HTTP POST request
r, err := http.NewRequest("POST", apiPath, strings.NewReader(body.Encode()))
if err != nil {
    fmt.Println(err)
    return
}
Enter fullscreen mode Exit fullscreen mode

Now, let's create a client and make the HTTP POST request using the method client.Do

If the returned error is nil, the res will contain a non-nil body which is the API response.

r.Header.Add("Content-Type", "application/x-www-form-urlencoded")

client := &http.Client{}
res, err := client.Do(r)
if err != nil {
    fmt.Println(err)
    return
}

defer res.Body.Close()
Enter fullscreen mode Exit fullscreen mode

Let's decode the JSON response using json.NewDecoder function that takes in the response body and a decode function that takes in a variable of type VonageResponse.

resp := &VonageResponse{}
derr := json.NewDecoder(res.Body).Decode(resp)
if derr != nil {
    fmt.Println(err)
    return
}
Enter fullscreen mode Exit fullscreen mode

We're expecting the Vonage API to return an array of Messages with a length of 1.

If the length is 0, it means there were some internal server errors. Please refer to the example JSON response above.

A Status of zero indicates success, a non-zero value means something went wrong.

if len(resp.Messages) <= 0 {
    fmt.Println("Vonage error: Internal Error")
    return
}

if resp.Messages[0].Status != "0" {
    fmt.Errorf("Vonage error: %v (status: %v)", resp.Messages[0].ErrorText, resp.Messages[0].Status)
    return
}

fmt.Println("SMS sent successfully.")
Enter fullscreen mode Exit fullscreen mode

Here is the complete working code.

package main

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

type VonageResponse struct {
    Messages []struct {
        Status    string `json:"status"`
        ErrorText string `json:"error-text"`
    } `json:"messages"`
}

func main() {
    apiKey := "<API Key>"
    apiSecret := "<API Secret>"
    apiPath := "https://rest.nexmo.com/sms/json"

    from := "Vonage APIs"
    to := "<From Number>"

    message := "Hello Vonage SMS API"

    // Request body
    body := url.Values{
        "from":         {from},
        "to":           {to},
        "text":         {message},
        "api_key":      {apiKey},
        "api_secret":   {apiSecret},
    }

    // Create a HTTP post request
    r, err := http.NewRequest("POST", apiPath, strings.NewReader(body.Encode()))
    if err != nil {
        fmt.Println(err)
        return
    }

    r.Header.Add("Content-Type", "application/x-www-form-urlencoded")

    client := &http.Client{}
    res, err := client.Do(r)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer res.Body.Close()

    resp := &VonageResponse{}
    derr := json.NewDecoder(res.Body).Decode(resp)
    if derr != nil {
        fmt.Println(err)
        return
    }

    if len(resp.Messages) <= 0 {
        fmt.Println("Vonage error: Internal Error")
        return
    }

    // A status of zero indicates success; a non-zero value means something went wrong.
    if resp.Messages[0].Status != "0" {
        fmt.Errorf("Vonage error: %v (status: %v)", resp.Messages[0].ErrorText, resp.Messages[0].Status)
        return
    }

    fmt.Println("SMS sent successfully.")
}
Enter fullscreen mode Exit fullscreen mode

I hope you found this article insightful.

Let's connect 🌎

Top comments (0)