SMS and MMS Notifications with Java and Spring

Today we'll build a Java and Spring sample application which demonstrates how to push SMS alerts on server exceptions.  We'll show you how to automatically notify your server administrators when something goes wrong, and cover the plumbing that makes it happen.

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 the Server Administrators - or Whomever Else - to Notify

Here we create a JSON list of administrators and whomever else should be notified if a server exception occurs.

The only essential piece of data we need is a phoneNumber for each person.

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

src/main/resources/administrators.json

Next, let's take a look at how to configure the Twilio REST client.

Configuring the Twilio REST Client

To send a message we'll need to initialize the TwilioRestClient as documented 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 Authorization Token will come directly from the Twilio console:

Twilio Account Summary section of the console

Click the eyeball icon to expose your Auth Token in a form you can copy and paste.

Loading Code Samples...
Language
package com.twilio.notifications.domain.twilio;

import com.twilio.http.TwilioRestClient;

public class Client {
    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) {
        messageCreator.create(to, credentials.getPhoneNumber(), message, mediaUrl);
    }
}
src/main/java/com/twilio/notifications/domain/twilio/Client.java
Configure Twilio Client

src/main/java/com/twilio/notifications/domain/twilio/Client.java

Next, we will see how to handle application exceptions and add in our new functionality.

Handling the Application Exceptions

Spring MVC provides several techniques to handle errors but in this case we are interested in handling all our application exceptions on our own.

For catching everything, we can use Global Exception Handling.

Loading Code Samples...
Language
package com.twilio.notifications.controller;

import com.twilio.notifications.domain.Administrator;
import com.twilio.notifications.domain.twilio.Client;
import com.twilio.notifications.service.AdministratorService;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
@SuppressWarnings("UnusedDeclaration")
public class GlobalExceptionController {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String handleAllException(Exception ex) {
        String message = customMessage(ex.getMessage());
        String mediaUrl = "http://goo.gl/ObTXdX";

        // Send a message to the administrators when something goes unexpectedly wrong.
        Administrator[] administrators = new AdministratorService().getAdministrators();
        for (Administrator administrator : administrators) {
            new Client().sendMessage(administrator.getPhoneNumber(), message, mediaUrl);
        }

        return "Something unexpected happened. Keep calm, administrators were notified.";
    }

    private String customMessage(String exceptionMessage) {
        return String.format("It appears the server is having Exception: %s " +
                        "Go to: http://newrelic.com for more details. " +
                        "Image URL: http://goo.gl/ObTXdX",
                        exceptionMessage);
    }
}
src/main/java/com/twilio/notifications/controller/GlobalExceptionController.java
Catch all exceptions in Spring with a Global Exception Controller

src/main/java/com/twilio/notifications/controller/GlobalExceptionController.java

Next up, let's see how to create a custom message.

Creating a Custom Alert Message

Here we craft the perfect alert message to send out via text message.

You might also decide to include a picture with your exception handling message. Perhaps a screenshot of the application when the crash happened?  Some infographics from somewhere?

Loading Code Samples...
Language
package com.twilio.notifications.controller;

import com.twilio.notifications.domain.Administrator;
import com.twilio.notifications.domain.twilio.Client;
import com.twilio.notifications.service.AdministratorService;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
@SuppressWarnings("UnusedDeclaration")
public class GlobalExceptionController {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String handleAllException(Exception ex) {
        String message = customMessage(ex.getMessage());
        String mediaUrl = "http://goo.gl/ObTXdX";

        // Send a message to the administrators when something goes unexpectedly wrong.
        Administrator[] administrators = new AdministratorService().getAdministrators();
        for (Administrator administrator : administrators) {
            new Client().sendMessage(administrator.getPhoneNumber(), message, mediaUrl);
        }

        return "Something unexpected happened. Keep calm, administrators were notified.";
    }

    private String customMessage(String exceptionMessage) {
        return String.format("It appears the server is having Exception: %s " +
                        "Go to: http://newrelic.com for more details. " +
                        "Image URL: http://goo.gl/ObTXdX",
                        exceptionMessage);
    }
}
src/main/java/com/twilio/notifications/controller/GlobalExceptionController.java
Custom exception message

src/main/java/com/twilio/notifications/controller/GlobalExceptionController.java

Let's look at how to load the list of lucky administrators.

Reading the Administrators from the JSON File

Next we read the admins (and the other lucky folks) from our JSON file.

We use the Gson Java library to convert our JSON text file into Administrator objects from our application.

Loading Code Samples...
Language
package com.twilio.notifications.service;


import com.google.gson.Gson;
import com.twilio.notifications.domain.Administrator;
import org.springframework.stereotype.Service;

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

@Service
public class AdministratorService {
    private String filePath;

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

    public AdministratorService(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/com/twilio/notifications/service/AdministratorService.java
Read the administrators from the JSON File

src/main/java/com/twilio/notifications/service/AdministratorService.java

Next up, let's look at 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 can as well, but the image will be included in the message body as a shortened URL.

Loading Code Samples...
Language
package com.twilio.notifications.domain.twilio;

import com.twilio.exception.TwilioException;
import com.twilio.http.TwilioRestClient;
import com.twilio.rest.api.v2010.account.Message;
import com.twilio.rest.api.v2010.account.MessageCreator;
import com.twilio.type.PhoneNumber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TwilioMessageCreator {

    private static final Logger logger = LoggerFactory.getLogger(TwilioMessageCreator.class);
    private final TwilioRestClient client;

    public TwilioMessageCreator(TwilioRestClient client) {
        this.client = client;
    }

    public void create(String to, String from, String body, String mediaUrl) {
        MessageCreator messageCreator = new MessageCreator(
                new PhoneNumber(to),
                new PhoneNumber(from),
                body);
        messageCreator.setMediaUrl(mediaUrl);
        try {
            messageCreator.create(this.client);
        } catch (TwilioException e) {
            logger.error(
                    "An exception occurred trying to send a message to {}, exception: {}",
                    to,
                    e.getMessage());
        }
    }
}
src/main/java/com/twilio/notifications/domain/twilio/TwilioMessageCreator.java
TwilioMessageCreator wrapper class

src/main/java/com/twilio/notifications/domain/twilio/TwilioMessageCreator.java

That's all, folks! 

We've just implemented an automated server notification system in Java and Spring that notifies all the right people when exceptions inevitably occur.

Now let's look at some other common features that are easy to add with the Java SDK.

Where to Next?

If you're a Java developer working with Twilio, you might want to check out these other tutorials.

Automated Survey

Don't let that valuable marketing data slip away!  Instantly collect structured data from your users with a survey conducted over a voice call or SMSes.

Appointment Reminders

Prevent no-shows by building an awesome Twilio-powered appointment reminder feature into your application.

Did this help?

Thanks for checking out this tutorial!

Tweet to us @twilio and let us know how it went, or what you're building next!

Agustin Camino
David Prothero
Andrew Baker
Paul Kamp
Samuel Mendes

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": "+5213321678083"
  }
]
package com.twilio.notifications.domain.twilio;

import com.twilio.http.TwilioRestClient;

public class Client {
    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) {
        messageCreator.create(to, credentials.getPhoneNumber(), message, mediaUrl);
    }
}
package com.twilio.notifications.controller;

import com.twilio.notifications.domain.Administrator;
import com.twilio.notifications.domain.twilio.Client;
import com.twilio.notifications.service.AdministratorService;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
@SuppressWarnings("UnusedDeclaration")
public class GlobalExceptionController {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String handleAllException(Exception ex) {
        String message = customMessage(ex.getMessage());
        String mediaUrl = "http://goo.gl/ObTXdX";

        // Send a message to the administrators when something goes unexpectedly wrong.
        Administrator[] administrators = new AdministratorService().getAdministrators();
        for (Administrator administrator : administrators) {
            new Client().sendMessage(administrator.getPhoneNumber(), message, mediaUrl);
        }

        return "Something unexpected happened. Keep calm, administrators were notified.";
    }

    private String customMessage(String exceptionMessage) {
        return String.format("It appears the server is having Exception: %s " +
                        "Go to: http://newrelic.com for more details. " +
                        "Image URL: http://goo.gl/ObTXdX",
                        exceptionMessage);
    }
}
package com.twilio.notifications.controller;

import com.twilio.notifications.domain.Administrator;
import com.twilio.notifications.domain.twilio.Client;
import com.twilio.notifications.service.AdministratorService;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
@SuppressWarnings("UnusedDeclaration")
public class GlobalExceptionController {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String handleAllException(Exception ex) {
        String message = customMessage(ex.getMessage());
        String mediaUrl = "http://goo.gl/ObTXdX";

        // Send a message to the administrators when something goes unexpectedly wrong.
        Administrator[] administrators = new AdministratorService().getAdministrators();
        for (Administrator administrator : administrators) {
            new Client().sendMessage(administrator.getPhoneNumber(), message, mediaUrl);
        }

        return "Something unexpected happened. Keep calm, administrators were notified.";
    }

    private String customMessage(String exceptionMessage) {
        return String.format("It appears the server is having Exception: %s " +
                        "Go to: http://newrelic.com for more details. " +
                        "Image URL: http://goo.gl/ObTXdX",
                        exceptionMessage);
    }
}
package com.twilio.notifications.service;


import com.google.gson.Gson;
import com.twilio.notifications.domain.Administrator;
import org.springframework.stereotype.Service;

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

@Service
public class AdministratorService {
    private String filePath;

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

    public AdministratorService(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 com.twilio.notifications.domain.twilio;

import com.twilio.exception.TwilioException;
import com.twilio.http.TwilioRestClient;
import com.twilio.rest.api.v2010.account.Message;
import com.twilio.rest.api.v2010.account.MessageCreator;
import com.twilio.type.PhoneNumber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TwilioMessageCreator {

    private static final Logger logger = LoggerFactory.getLogger(TwilioMessageCreator.class);
    private final TwilioRestClient client;

    public TwilioMessageCreator(TwilioRestClient client) {
        this.client = client;
    }

    public void create(String to, String from, String body, String mediaUrl) {
        MessageCreator messageCreator = new MessageCreator(
                new PhoneNumber(to),
                new PhoneNumber(from),
                body);
        messageCreator.setMediaUrl(mediaUrl);
        try {
            messageCreator.create(this.client);
        } catch (TwilioException e) {
            logger.error(
                    "An exception occurred trying to send a message to {}, exception: {}",
                    to,
                    e.getMessage());
        }
    }
}