SMS and MMS Notifications with Java and Spark

Download the Code

Today we'll look at a Spark sample application that demonstrates how to send SMS alerts to your system administrators when something goes wrong on your server. We'll do a deep dive on all of the plumbing so you can see how easy it'll be to add notifications to your own application.

See how EMC uses Twilio SMS to send IT alerts to 68,000 employees.

Let's get started!

Click the button below to move to the next step of the tutorial.

List Your Server Administrators, and Whomever Else

Here we create a JSON list of administrators who should be notified if a server error occurs.

The only essential piece of data we need is a phone_number for each administrator.

Loading Code Samples...
Language
[
  {
    "name": "Bob",
    "phoneNumber": "+12025550197"
  },
  {
    "name": "Alice",
    "phoneNumber": "+12025550890"
  }
]
src/main/resources/administrators.json
JSON Administrator list

src/main/resources/administrators.json

Next, let's take a look at configuring the Twilio REST Client.

Configuring the Twilio REST Client

To send a message we'll need to initialize the TwilioRestClient defined in the Twilio Java Helper Library. It requires reading a TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN from environment variables.

The values for your account SID and Auth Token will be in the Twilio console:

Twilio Account Summary section of the console

Click the eyeball to show your Auth Token to copy and paste.

Loading Code Samples...
Language
package utils;

import com.twilio.exception.TwilioException;
import com.twilio.http.TwilioRestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Client {

    private static Logger logger = LoggerFactory.getLogger(Client.class);


    private Credentials credentials;
    private TwilioMessageCreator messageCreator;

    public Client() {
        this.credentials = new Credentials();
        this.messageCreator = new TwilioMessageCreator(
                new TwilioRestClient.Builder(credentials.getAccountSid(), credentials.getAuthToken()).build()
        );
    }

    public Client(TwilioMessageCreator messageCreator, Credentials credentials) {
        this.credentials = credentials;
        this.messageCreator = messageCreator;
    }

    public void sendMessage(String to, String message, String mediaUrl) {
        try {
            messageCreator.create(to, credentials.getPhoneNumber(), message, mediaUrl);
        } catch (TwilioException e) {
            logger.error("An exception occurred trying to send the message \"{}\" to {}." +
                    " \nTwilio returned: {} \n", message, to, e.getMessage());
        }
    }
}
src/main/java/utils/Client.java
Get Twilio Account SID and Auth Token credentials

src/main/java/utils/Client.java

Next up, we will look at how to handle application exceptions.

Handling the Application Exceptions

In a Spark application, we can handle exceptions of a configured type for all routes and filters by using exception mapping.  This is also where we'll eventually loop through the list and send our alerts.

Loading Code Samples...
Language
import logging.LoggingFilter;
import models.Administrator;
import utils.Client;
import utils.Repository;

import static spark.Spark.afterAfter;
import static spark.Spark.exception;
import static spark.Spark.get;

public class App {
    public static void main(String[] args) {
        get("/", (request, response) -> {
            throw new Exception("Impossible happened");
        });

        // http://sparkjava.com/documentation.html#exception-mapping
        exception(Exception.class, (e, request, response) -> {
            String message = String.format("It appears the server is having Exception: %s " +
                    "Go to: http://newrelic.com for more details. " +
                    "Image URL: http://goo.gl/ObTXdX",
                    e.getMessage());

            String mediaUrl = "http://goo.gl/ObTXdX";

            Administrator[] administrators = new Repository().getAdministrators();
            for(Administrator administrator : administrators) {
                new Client().sendMessage(administrator.getPhoneNumber(), message, mediaUrl);
            }

            response.body("Something unexpected happened. Keep calm, administrators were notified.");
        });

        // Log all requests and responses
        afterAfter(new LoggingFilter());
    }
}
src/main/java/App.java
Raise an exception

src/main/java/App.java

Now let's look at how to create a custom message for our notifications.

Create a Custom Alert Message

Here we create an alert message to send out via text message.

You might also decide to include a picture with your alert message and make it an MMS. Perhaps a screenshot of the application when the crash happened?  An 'Everything is Okay' meme image?

Loading Code Samples...
Language
import logging.LoggingFilter;
import models.Administrator;
import utils.Client;
import utils.Repository;

import static spark.Spark.afterAfter;
import static spark.Spark.exception;
import static spark.Spark.get;

public class App {
    public static void main(String[] args) {
        get("/", (request, response) -> {
            throw new Exception("Impossible happened");
        });

        // http://sparkjava.com/documentation.html#exception-mapping
        exception(Exception.class, (e, request, response) -> {
            String message = String.format("It appears the server is having Exception: %s " +
                    "Go to: http://newrelic.com for more details. " +
                    "Image URL: http://goo.gl/ObTXdX",
                    e.getMessage());

            String mediaUrl = "http://goo.gl/ObTXdX";

            Administrator[] administrators = new Repository().getAdministrators();
            for(Administrator administrator : administrators) {
                new Client().sendMessage(administrator.getPhoneNumber(), message, mediaUrl);
            }

            response.body("Something unexpected happened. Keep calm, administrators were notified.");
        });

        // Log all requests and responses
        afterAfter(new LoggingFilter());
    }
}
src/main/java/App.java
Custom exception message

src/main/java/App.java

Let's move forward and look at loading the list of administrators.

Reading the Administrators from a JSON File

Next, we read the admins - and any other lucky people - from our JSON file. We use the Gson Java library to convert our JSON text file into Administrator objects.

Loading Code Samples...
Language
package utils;

import com.google.gson.Gson;
import models.Administrator;

import java.io.FileNotFoundException;
import java.io.FileReader;

public class Repository {
    private String filePath;

    public Repository() {
        this.filePath = getClass().getClassLoader().getResource("administrators.json").getPath();
    }

    public Repository(String filePath) {
        this.filePath = filePath;
    }

    public Administrator[] getAdministrators() {
        try {
            return new Gson().fromJson(new FileReader(filePath), Administrator[].class);
        } catch (FileNotFoundException e) {
            e.printStackTrace();

            return new Administrator[0];
        }
    }
}
src/main/java/utils/Repository.java
Read the administrator list from disk

src/main/java/utils/Repository.java

And next, we will see how to send a text message.

Sending a Text Message

There are three parameters needed to send an SMS using the Twilio REST API: From, To, and Body.

US and Canadian phone numbers can also send an image with the message.  Other countries will have the image URL automatically shortened and appended to the body.

Loading Code Samples...
Language
package utils;

import com.twilio.exception.TwilioException;
import com.twilio.http.TwilioRestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Client {

    private static Logger logger = LoggerFactory.getLogger(Client.class);


    private Credentials credentials;
    private TwilioMessageCreator messageCreator;

    public Client() {
        this.credentials = new Credentials();
        this.messageCreator = new TwilioMessageCreator(
                new TwilioRestClient.Builder(credentials.getAccountSid(), credentials.getAuthToken()).build()
        );
    }

    public Client(TwilioMessageCreator messageCreator, Credentials credentials) {
        this.credentials = credentials;
        this.messageCreator = messageCreator;
    }

    public void sendMessage(String to, String message, String mediaUrl) {
        try {
            messageCreator.create(to, credentials.getPhoneNumber(), message, mediaUrl);
        } catch (TwilioException e) {
            logger.error("An exception occurred trying to send the message \"{}\" to {}." +
                    " \nTwilio returned: {} \n", message, to, e.getMessage());
        }
    }
}
src/main/java/utils/Client.java
Twilio Client wrapper to facilitate sending SMS and MMS messages

src/main/java/utils/Client.java

And that's a wrap!

We've just implemented an automated server notification system for Java and Spark that can push server alerts if anything goes wrong.

Let's see what else you can do with the Twilio Java SDK, next.

Where to Next?

We love Java here at Twilio.  Here're just a couple more examples of using our Java SDK to easily add some features in your application:

Automated Survey

How well is your team doing when interacting with customers?  Instantly collect structured data from your users with a survey conducted over a voice call or SMS.

Appointment Reminders

A simple tutorial to prevent no-shows at your business - send your customers automatic appointment notifications.

Did this help?

Thanks for building with us today.  Tweet us a comment @twilio to let us know what you think and what you're building!

Agustin Camino
Paul Kamp
Andrew Baker
Jose Oliveros

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

1 / 1
Loading Code Samples...
[
  {
    "name": "Bob",
    "phoneNumber": "+12025550197"
  },
  {
    "name": "Alice",
    "phoneNumber": "+12025550890"
  }
]
package utils;

import com.twilio.exception.TwilioException;
import com.twilio.http.TwilioRestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Client {

    private static Logger logger = LoggerFactory.getLogger(Client.class);


    private Credentials credentials;
    private TwilioMessageCreator messageCreator;

    public Client() {
        this.credentials = new Credentials();
        this.messageCreator = new TwilioMessageCreator(
                new TwilioRestClient.Builder(credentials.getAccountSid(), credentials.getAuthToken()).build()
        );
    }

    public Client(TwilioMessageCreator messageCreator, Credentials credentials) {
        this.credentials = credentials;
        this.messageCreator = messageCreator;
    }

    public void sendMessage(String to, String message, String mediaUrl) {
        try {
            messageCreator.create(to, credentials.getPhoneNumber(), message, mediaUrl);
        } catch (TwilioException e) {
            logger.error("An exception occurred trying to send the message \"{}\" to {}." +
                    " \nTwilio returned: {} \n", message, to, e.getMessage());
        }
    }
}
import logging.LoggingFilter;
import models.Administrator;
import utils.Client;
import utils.Repository;

import static spark.Spark.afterAfter;
import static spark.Spark.exception;
import static spark.Spark.get;

public class App {
    public static void main(String[] args) {
        get("/", (request, response) -> {
            throw new Exception("Impossible happened");
        });

        // http://sparkjava.com/documentation.html#exception-mapping
        exception(Exception.class, (e, request, response) -> {
            String message = String.format("It appears the server is having Exception: %s " +
                    "Go to: http://newrelic.com for more details. " +
                    "Image URL: http://goo.gl/ObTXdX",
                    e.getMessage());

            String mediaUrl = "http://goo.gl/ObTXdX";

            Administrator[] administrators = new Repository().getAdministrators();
            for(Administrator administrator : administrators) {
                new Client().sendMessage(administrator.getPhoneNumber(), message, mediaUrl);
            }

            response.body("Something unexpected happened. Keep calm, administrators were notified.");
        });

        // Log all requests and responses
        afterAfter(new LoggingFilter());
    }
}
import logging.LoggingFilter;
import models.Administrator;
import utils.Client;
import utils.Repository;

import static spark.Spark.afterAfter;
import static spark.Spark.exception;
import static spark.Spark.get;

public class App {
    public static void main(String[] args) {
        get("/", (request, response) -> {
            throw new Exception("Impossible happened");
        });

        // http://sparkjava.com/documentation.html#exception-mapping
        exception(Exception.class, (e, request, response) -> {
            String message = String.format("It appears the server is having Exception: %s " +
                    "Go to: http://newrelic.com for more details. " +
                    "Image URL: http://goo.gl/ObTXdX",
                    e.getMessage());

            String mediaUrl = "http://goo.gl/ObTXdX";

            Administrator[] administrators = new Repository().getAdministrators();
            for(Administrator administrator : administrators) {
                new Client().sendMessage(administrator.getPhoneNumber(), message, mediaUrl);
            }

            response.body("Something unexpected happened. Keep calm, administrators were notified.");
        });

        // Log all requests and responses
        afterAfter(new LoggingFilter());
    }
}
package utils;

import com.google.gson.Gson;
import models.Administrator;

import java.io.FileNotFoundException;
import java.io.FileReader;

public class Repository {
    private String filePath;

    public Repository() {
        this.filePath = getClass().getClassLoader().getResource("administrators.json").getPath();
    }

    public Repository(String filePath) {
        this.filePath = filePath;
    }

    public Administrator[] getAdministrators() {
        try {
            return new Gson().fromJson(new FileReader(filePath), Administrator[].class);
        } catch (FileNotFoundException e) {
            e.printStackTrace();

            return new Administrator[0];
        }
    }
}
package utils;

import com.twilio.exception.TwilioException;
import com.twilio.http.TwilioRestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Client {

    private static Logger logger = LoggerFactory.getLogger(Client.class);


    private Credentials credentials;
    private TwilioMessageCreator messageCreator;

    public Client() {
        this.credentials = new Credentials();
        this.messageCreator = new TwilioMessageCreator(
                new TwilioRestClient.Builder(credentials.getAccountSid(), credentials.getAuthToken()).build()
        );
    }

    public Client(TwilioMessageCreator messageCreator, Credentials credentials) {
        this.credentials = credentials;
        this.messageCreator = messageCreator;
    }

    public void sendMessage(String to, String message, String mediaUrl) {
        try {
            messageCreator.create(to, credentials.getPhoneNumber(), message, mediaUrl);
        } catch (TwilioException e) {
            logger.error("An exception occurred trying to send the message \"{}\" to {}." +
                    " \nTwilio returned: {} \n", message, to, e.getMessage());
        }
    }
}