Blog

How to send SMS with Java (with code examples)

Amy Elliott Amy Elliott
· 16 min read · Tips and resources · November 27th, 2024
Java is a strong choice for sending SMS thanks to its stability, platform independence, and support for the majority of SMS gateways.

Java is also one of the most widely-used programming languages and ensures reliable delivery and scalability thanks to support for multithreading. This makes it an excellent option for a more future-proof solution you can stick with for your Java application as your SMS-sending needs grow. 

Many developers are adding SMS to optimize system notification delivery because recipients are more likely to pay attention to and open them. This is especially important for transactional messaging, as these messages often contain critical information and enhance the user experience. 

So let’s get into it. In this tutorial, we’ll cover how to get started, how to send SMS messages, additional features such as personalization, the MailerSend SMS API messaging service, and best practices.

Getting started sending SMS using Java

For this guide, we’ll use the MailerSend SMS API and Java SDK to send text messages. 

Note:

SMS is currently available in The U.S. and Canada. Availability in other regions is coming soon!

Prerequisites

Before you get started, make sure you have the following ready to go:

  • Java JDK 17 or higher installed: You can download the Java JDK from the Oracle website or verify your version with java -version in your terminal

  • MailerSend account and API key: Sign up for a MailerSend account. It’s free to sign up and send emails, however, a paid account is needed to access the SMS feature. Create a new API key with the correct permissions for sending SMS and copy it. Check out the guide on managing and creating API keys

  • MailerSend phone number: All paid plans have a free trial phone number for testing purposes and a number of free SMS. You can also purchase a phone number to start sending. Note: Purchased phone numbers must be verified

  • A new Java project: Create a new project in your IDE (Integrated Development Environment) of choice

Check out our guide on how to start sending SMS and our API reference.

Step 1: Add your dependencies

For this example, we’re using Maven. Add the following dependency to install the MailerSend Java SDK to your pom.xml.

<dependency>
  <groupId>com.mailersend</groupId>
  <artifactId>java-sdk</artifactId>
  <version>1.0.1</version>
</dependency>

Step 2: Set your environment variables

Do not forgo using environment variables! This is a critical step to keep sensitive information, such as API keys, secure and unexposed in your code. We’ll set the variables for our API key and recipient phone number in this example. 

In Linux/macOS (Temporary)

Set the variables in the terminal:

export MAILERSEND_API_KEY="your_api_key"
export SMS_RECIPIENT_NUMBER="+1234567890"
export SMS_FROM_NUMBER="+0987654321"

In Linux/macOS (Permanent)

Open your shell configuration file. For Bash users:

nano ~/.bashrc

For Zsh users:

nano ~/.zshrc

Add the following at the end of the file to set the variables:

export MAILERSEND_API_KEY="your_api_key"
export SMS_RECIPIENT_NUMBER="+1234567890"
export SMS_FROM_NUMBER="+0987654321"

Save the file and reload it. For Bash users:

source ~/.bashrc

For Zsh users:

source ~/.zshrc

Alternatively, you can set the environment variables in your IDE by editing them in your configuration. You can also set them in Windows by going to System Properties > Environment Variables.

Step 3: Send your first SMS

In your Java project, create a new class, we’ve named it SendSmsExample. Use the following Java code to send an SMS text message. For this example, we’ve set the message text to include a dynamic security code or OTP (One-time password) using a personalization variable.

import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.exceptions.MailerSendException;

public class SendSmsExample {

    public void sendSms() {
        // Fetch the API token and phone numbers from environment variables
        String apiKey = System.getenv("MAILERSEND_API_KEY");
        String fromPhoneNumber = System.getenv("SMS_FROM_NUMBER");
        String toPhoneNumber = System.getenv("SMS_RECIPIENT_NUMBER");
        
        if (apiKey == null || fromPhoneNumber == null || toPhoneNumber == null) {
            System.out.println("Please make sure that the required environment variables are set.");
            return;
        }

        // Initialize MailerSend with the API token
        MailerSend ms = new MailerSend();
        ms.setToken(apiKey);

        try {
            // Build the SMS request
            String messageId = ms.sms().builder()
                .from(fromPhoneNumber)  // 'from' phone number
                .addRecipient(toPhoneNumber)  // 'to' phone number
                .text("Your security code is {{auth_code}}. This code will remain active for 15 minutes.")  // Message text, with personalization
                .addPersonalization(toPhoneNumber, "auth_code", "760465")  // Personalization with dynamic OTP
                .send();  // Send the message
            
            // Print the message ID on success
            System.out.println("Message sent with ID: " + messageId);
            
        } catch (MailerSendException e) {
            // Handle exceptions from the MailerSend API
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SendSmsExample smsExample = new SendSmsExample();
        smsExample.sendSms();
    }
}

You can then save your changes and run the SendSmsExample class. If everything has been configured correctly, the above command will send the SMS message to the number that you entered into the `SMS_FROM_NUMBER` variable.

Error handling

The above code example includes methods for sufficient error handling and troubleshooting sending issues. 

MailerSendException is thrown by the MailerSend SDK if any errors occur while interacting with the API.

} catch (MailerSendException e) {
    // Handle exceptions from the MailerSend API
    e.printStackTrace();
}

For example, if the API key is invalid, the phone numbers are incorrect, or there are network issues, the MailerSendException is caught and the error details are printed using e.printStackTrace().

What’s more, the following code snippet:

if (apiKey == null || fromPhoneNumber == null || toPhoneNumber == null) {
    System.out.println("Please make sure that the required environment variables are set.");
    return;
}

Checks if the environment variables are valid or null. If a variable is found to be null, it will print a message indicating that the variables haven’t been sent. The method will then exit, preventing the program from sending an SMS message with incomplete or missing information.

Other features of the MailerSend API

When you’ve set everything up and started sending SMSes, there are a bunch of other API features to explore that can help optimize your processes. Here’s a quick rundown of each one:

Managing SMS activities

The sms-activity endpoint allows you to retrieve SMS activities including processed, queued, sent, delivered, or failed for a specific phone number or message. This is useful in ensuring that your messages are being delivered and identifying any potential issues.

You can use the following GET request to fetch a list of activities:

GET https://api.mailersend.com/v1/sms-activity

Here’s what the HTTP request body would look like:

import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.sms.activities.SmsActivityList;
import com.mailersend.sdk.sms.activities.SmsActivity;

public class SmsActivityExample {

    public void getActivities() {
        // Fetch the API token from environment variables
        String apiKey = System.getenv("MAILERSEND_API_KEY");

        if (apiKey == null) {
            System.out.println("Please set the MAILERSEND_API_KEY environment variable.");
            return;
        }

        MailerSend ms = new MailerSend();
        ms.setToken(apiKey);

        try {
            // Fetch SMS activities list
            SmsActivityList list = ms.sms().activities().getActivities();

            // Loop through the SMS activities and print details
            for (SmsActivity activity : list.smsActivities) {
                System.out.println("Activity ID: " + activity.smsMessageId);
                System.out.println("Content: " + activity.content);
    System.out.println("Status: " + activity.status);
                // Add more fields if needed
            }

        } catch (MailerSendException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SmsActivityExample example = new SmsActivityExample();
        example.getActivities();
    }
}

If valid, the response will look something like this:

{
	"data": [
		{
			"from": "+18332647501",
			"to": "+16203221059",
			"created_at": "2022-02-21T08:15:46.627000Z",
			"content": "Your security code is {{auth_code}}. This code will remain active for 15 minutes.",
			"status": "delivered",
            "sms_message_id": "62134a2d7de3253bf10d6642"
		},
        {
          "from": "+18332647501",
          "to": "+16203221059",
          "created_at": "2022-02-21T08:15:42.508000Z",
          "content": "Your security code is {{auth_code}}. This code will remain active for 15 minutes.",
          "status": "processed",
          "sms_message_id": "62134a2d7de3253bf10d6642"
        },
        {
          "from": "+18332647501",
          "to": "+16203221059",
          "created_at": "2022-02-21T08:15:42.579000Z",
          "content": "Your security code is {{auth_code}}. This code will remain active for 15 minutes.",
          "status": "queued",
          "sms_message_id": "62134a2d7de3253bf10d6642"
        },
        {
          "from": "+18332647501",
          "to": "+16203221059",
          "created_at": "2022-02-21T08:15:43.624000Z",
          "content": "Your security code is {{auth_code}}. This code will remain active for 15 minutes.",
          "status": "sent",
          "sms_message_id": "62134a2d7de3253bf10d6642"
        }
	],
	"links": {
		"first": "https:\/\/api.mailersend.com\/v1\/sms-activity?page=1",
		"last": null,
		"prev": null,
		"next": "https:\/\/api.mailersend.com\/v1\/sms-activity?page=2"
	},
	"meta": {
		"current_page": 1,
		"from": 1,
		"path": "https:\/\/api.mailersend.com\/v1\/sms-activity",
		"per_page": 25,
		"to": 1
	}
}

Handling SMS recipients

With the sms-recipients endpoint, you can use the API to manage recipients by fetching a list of recipients and their details, fetching the details about a specific recipient, and updating a specific recipient. 

This will allow you to check when the recipient was created, and more importantly, their status: whether they are active or have opted out of receiving SMS messages. 

To fetch a list of recipients, use the following GET request:

GET  https://api.mailersend.com/v1/sms-recipients

The request body should look something like this:

import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.sms.recipients.SmsRecipient;
import com.mailersend.sdk.sms.recipients.SmsRecipientList;

public class SmsRecipientExample {

    public void getSmsRecipients() {
        // Fetch the API token from environment variables
        String apiKey = System.getenv("MAILERSEND_API_KEY");

        if (apiKey == null) {
            System.out.println("Please set the MAILERSEND_API_KEY environment variable.");
            return;
        }

        MailerSend ms = new MailerSend();
        ms.setToken(apiKey);

        try {
            // Fetch list of SMS recipients
            SmsRecipientList list = ms.sms().recipients().getRecipients();

            // Loop through each recipient and print their ID
            for (SmsRecipient recipient : list.recipients) {
                System.out.println("Recipient ID: " + recipient.id);
            }

        } catch (MailerSendException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SmsRecipientExample example = new SmsRecipientExample();
        example.getSmsRecipients();
    }
}

If valid, the response will look like this:

{
  "data": [
    {
      "id": "62347d2be979fd275c0afd34",
      "number": "+1234567890",
      "status": "active",
      "created_at": "2022-01-01T12:00:0003.000000Z"
    },
 {
      "id": "66017d2be379rd275c0kgb37",
      "number": "+1234512345",
      "status": "active",
      "created_at": "2022-02-02T12:00:0003.000000Z"
    },
 {
      "id": "58247k4ne979fd083c0ngb71",
      "number": "+0987654321",
      "status": "opt_out",
      "created_at": "2022-03-03T12:00:0003.000000Z"
    },
  ]
}

And you can update the status (active, opt_out) for a specific recipient with a PUT request:

PUT https://api.mailersend.com/v1/sms-recipients/{sms_recipient_id}
import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.sms.recipients.SmsRecipient;

public class SmsRecipientUpdateExample {

    public void updateSmsRecipient() {
        // Fetch the API token from environment variables
        String apiKey = System.getenv("MAILERSEND_API_KEY");

        if (apiKey == null || apiKey.isEmpty()) {
            System.out.println("Error: MAILERSEND_API_KEY environment variable is not set.");
            return;
        }

        MailerSend ms = new MailerSend();
        ms.setToken(apiKey);

        try {
            String status = "opt_out";

            SmsRecipient recipient = ms.sms().recipients().updateRecipient("66017d2be379rd275c0kgb37", status);
            
            // Print the updated status
            System.out.println("Recipient status updated to: " + recipient.status);

        } catch (MailerSendException e) {
            System.out.println("MailerSend API Exception: " + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            System.out.println("An unexpected error occurred: " + e.getMessage());
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SmsRecipientUpdateExample example = new SmsRecipientUpdateExample();
        example.updateSmsRecipient();
    }
}

And the valid response would be:

{
  "data": {
    "id": "66017d2be379rd275c0kgb37",
    "number": "+1234512345",
    "status": "opt_out",
    "created_at": "2022-02-02T12:00:0003.000000Z"
  }
}

Managing inbound SMS routes

While you can easily create inbound routes in the MailerSend app, you can also manage inbound routes via the API. The sms-inbounds endpoint allows you to:

  • Get a list of inbound SMS routes

  • Get a single inbound SMS route

  • Add, update, or delete an inbound SMS route

Inbound routes are a great way to implement support via SMS, ensuring that incoming messages are correctly processed and routed to the appropriate destination. You can also use this functionality to parse incoming SMS contents to another application. Let’s take a look at how to create a new inbound route.

Use the following POST request:

POST https://api.mailersend.com/v1/sms-inbounds
import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.sms.inboundroutes.SmsInboundRoute;

public class SmsInboundRouteExample {

    public void addSmsInboundRoute() {
        // Fetch the API token from environment variables
        String apiKey = System.getenv("MAILERSEND_API_KEY");

        if (apiKey == null || apiKey.isEmpty()) {
            System.out.println("Error: MAILERSEND_API_KEY environment variable is not set.");
            return;
        }

        MailerSend ms = new MailerSend();
        ms.setToken(apiKey);

        try {
            SmsInboundRoute route = ms.sms().inboundRoutes().builder()
                    .smsNumberId("7z3m5jgrogdpyo6n")  // Replace with own SMS number ID
                    .name("Test inbound route")
                    .enabled(false)
                    .forwardUrl("https://example.com")
                    .filter("equal", "START")
                    .addSmsInboundRoute();

            System.out.println("Inbound Route ID: " + route.id);

        } catch (MailerSendException e) {
            System.out.println("MailerSend API Exception: " + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            System.out.println("An unexpected error occurred: " + e.getMessage());
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SmsInboundRouteExample example = new SmsInboundRouteExample();
        example.addSmsInboundRoute();
    }
}

And the valid response:

{
  "data": {
    "id": "7z3m5jgrogdpyo6n",
    "name": "Test inbound route",
    "filter": {
      "value": "START",
      "comparer": "equal"
    },
    "forward_url": "https://example.com",
    "enabled": true,
    "secret": "jYhafGtTiZgw0qWxlkUA7cbqTG3Zfh2j",
    "created_at": "2022-01-01T12:00:00.000000Z"
  }
}

Managing SMS webhooks

SMS webhooks allow you to listen for events and get real-time notifications about your SMS messages. You can use these notifications to create workflows that use the events to trigger actions within your integrations, for example, sending a Slack message when an SMS fails.

With the sms-webhooks endpoint, you can:

  • Get a list of SMS webhooks

  • Get a single SMS webhook

  • Create, update, or delete an SMS webhook

Here’s the POST request for creating an SMS webhook:

POST https://api.mailersend.com/v1/sms-webhooks/
import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.sms.webhooks.SmsWebhook;

public class SmsWebhookExample {

    public void createSmsWebhook() {
        // Fetch the API token from environment variables
        String apiKey = System.getenv("MAILERSEND_API_KEY");

        if (apiKey == null || apiKey.isEmpty()) {
            System.out.println("Error: MAILERSEND_API_KEY environment variable is not set.");
            return;
        }

        MailerSend ms = new MailerSend();
        ms.setToken(apiKey);

        try {
            SmsWebhook webhook = ms.sms().webhooks().builder()
                    .addEvent("sms.sent")
                    .name("sms webhook")
                    .url("https://example.com")
                    .createWebhook("7z3m5jgrogdpyo6n");  // Replace with your own SMS phone number ID

            System.out.println("Webhook ID: " + webhook.id);

        } catch (MailerSendException e) {
            System.out.println("MailerSend API Exception: " + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            System.out.println("An unexpected error occurred: " + e.getMessage());
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SmsWebhookExample example = new SmsWebhookExample();
        example.createSmsWebhook();
    }
}

7 tips for testing and debugging your SMS configuration

1. Start out with test features and phone numbers

SMS providers enforce strict regulations and guidelines for their users, so it’s important to start out with a test environment and avoid using real phone numbers to get things set up. All MailerSend users on a paid plan get a free trial phone number, enabling them to easily test the tools without using a purchased number. 

2. Validate your API keys and their permissions

Make sure that any API keys you are using are correct; some services may provide different API keys for testing and production environments, so keep that in mind. You’ll also need to make sure that the API keys you intend to use for sending SMS have the necessary permissions.

3. Keep and monitor activity logs

Error and response logs will be your first port of call during troubleshooting and setting up SMS sending. Viewing the response logs from your API calls will allow you to confirm the success of your configuration, or get insights from error messages should your requests fail.

4. Simulate atypical cases and outliers

To have the best understanding of your SMS system, test out atypical cases to understand how it handles them. For example, long text messages over 160 characters are typically split into multiple messages, so you could test this to see if they are split correctly. If you are using inbound routing, you could test how the system handles SMS from international numbers, or how it processes messages containing emojis. 

5. Test for failure as well as success

It’s just as important to understand how your system handles failures and errors as it does successful requests. Test different scenarios such as invalid phone numbers and null variables to see how your error handling performs.

6. Review response times

Monitor how long it takes for an SMS to be sent after the request has been made as well as how long messages are queued for. Some types of SMS messages, such as OTPs and 2FA (two-factor authentication), are extremely time-dependent and need to be delivered as soon as possible. Understanding the latency of your system can help you to assess performance and make adjustments. 

7. Use MailerSend’s built-in testing feature

In the com.mailersend.sdk.tests package, change the properties in the TestHelper class to match with your account details. Then run:

mvn test

Best practices for sending SMS with Java

1. Always use environment variables for sensitive information

Never hardcode API keys or other sensitive data into your code. Using environment variables will allow you to securely access them in your programs while preventing them from being exposed. 

2. Ensure proper error handling

Catching and logging exceptions with try-catch blocks will allow your system to gracefully handle errors so that it can operate smoothly at all times. It will also make it easier for you to identify where any issues lie. 

3. Validate phone numbers

There are libraries available that you can use to validate phone numbers before sending an SMS. One example of this is Google’s phone number library, libphonenumber. You should also ensure that all recipients are active and haven’t opted out from receiving your text messages.

4. Segment long messages

Messages longer than 160 characters should be split into multiple text messages. If you’re using an SMS API like MailerSend, this functionality is built-in. 

5. Use asynchronous requests when handling high volumes of SMS

When sending a high volume of messages, you can use Java’s concurrency features to enable asynchronous sending. While this doesn’t work directly with MailerSend (as it uses synchronous methods), you can use this feature by wrapping the MailerSend method in an async task. Here’s an example using Java’s CompletableFuture feature.

import java.util.concurrent.CompletableFuture;
import com.mailersend.sdk.MailerSend;
import com.mailersend.sdk.exceptions.MailerSendException;
import com.mailersend.sdk.sms.recipients.SmsRecipient;

public class SmsSender {
    
    public CompletableFuture<Void> sendSmsAsync(String phoneNumber, String message) {
        return CompletableFuture.runAsync(() -> {
            // Create the MailerSend instance
            MailerSend ms = new MailerSend();
            ms.setToken(System.getenv("MAILERSEND_API_KEY"));
            
            try {
                // Send SMS message synchronously
String messageId = ms.sms().builder()
.text(“Hello from MailerSend!”)
.from(fromPhoneNumber) 
.addRecipient(toPhoneNumber)
.send();
               
                System.out.println("Message sent to " + phoneNumber);
            } catch (MailerSendException e) {
                System.out.println("Error sending SMS to " + phoneNumber + ": " + e.getMessage());
            }
        });
    }

    public static void main(String[] args) {
        SmsSender smsSender = new SmsSender();
        
        // Send SMS asynchronously
        smsSender.sendSmsAsync("1234567890", "Hello from MailerSend!")
            .thenRun(() -> System.out.println("SMS process completed."))
            .get();
    }
}

Check out our guide on SMS compliance for more best practices.

Scalable and efficient SMS sending with Java

Sending text messages via MailerSend’s API is a simple and efficient way to get important notifications to users and customers. Combined with Java’s reliability, widespread support and popularity, and notable potential for scalability, it’s a solution worth serious consideration if you’re a developer looking for hassle-free SMS sending for your website or app.

Get started with MailerSend's SMS API

Start sending SMS now with MailerSend's Java SDK. Get a trial phone number to test SMS sending for free with any premium plan.

Got any tips and tricks for sending SMS with Java? Let us know in the comments.

Amy Elliott
I’m Amy, Content Writer at MailerSend. As a child, I dreamt about writing a book and practiced by tearing pages from an A4 notepad and binding them with sugar paper. The book is pending but in the meantime, I love taking a deep dive into technical topics and sharing insights on email metrics and deliverability.