How to Send Bulk Emails With Spring Boot and Twilio

August 14, 2023
Written by
Antonello Zanini
Contributor
Opinions expressed by Twilio contributors are their own
Reviewed by

header - How to Send Bulk Emails With Spring Boot and Twilio

In today's digital age, emails have become an integral part of our lives. We tend to refresh our email clients dozens of times a day and spend countless hours responding to new messages. This makes email an incredibly powerful tool for reaching and engaging a wide audience.

In this tutorial, you will learn three approaches to sending bulk Emails with the Twilio SendGrid Email API in Spring Boot.

Prerequisites

Here are the prerequisites you need to meet to follow this tutorial:

Click the links above and follow the instructions to download, install, and configure everything you need.

If you do not have a Spring Boot project or prefer to start from scratch, initialize a new one with Spring Initializr as below:

Screenshot of Spring Initializr with filled out fields

Compile the form as follows:

  • Group: com.twilio
  • Artifact: bulkemails
  • Name: bulkemails
  • Description: Bulk emails using Twilio SendGrid in Spring Boot
  • Package name: com.twilio.bulkemails
  • Packaging: Jar
  • Java: 17

Note the selection of “Gradle - Groovy” as the building automation tool. “Maven” will also do. Click the ADD DEPENDENCIES... button in the upper right corner and select the “Spring Web” dependency.

When you are done, click GENERATE to download a .zip file containing your new Spring Boot Web project. Extract the archive and open the project folder in IntelliJ IDEA. Wait for the first Gradle build to complete, and you can now write some code.

Opening the project in IntelliJ IDEA

Integrate SendGrid in Spring Boot

Time to retrieve a Twilio SendGrid API key and get your project ready to send emails!

Create a SendGrid API key

Follow the steps below to get started with Twilio SendGrid:

Sign up for a free SendGrid account: Fill out the registration form and follow the instructions.

Enable two-factor authentication: SendGrid forces you to enable 2FA (two-factor authentication) via SMS or the Authy app.

Create a SendGrid API key: Visit the API key section of your SendGrid dashboard and create a new API with full access permissions. Let’s call it “bulk email:”

Creating a SendGrid API key

Click “Create & View” and the following modal will open:

Getting the SendGrid API key

Copy the API key and store it in a safe place. You will need it soon.

Verify your sender identity: To ensure the sender’s reputation, Twilio SendGrid requires you to verify the identity of your “From” email address by completing domain authentication. Read the documentation to learn more about this process.

Add the Twilio SendGrid Java Helper Library to the project dependencies

You now have everything you need to integrate the Twilio SendGrid Java Helper library into your project. This package makes it easy to interact with the SendGrid Email API, equipping you with utilities to send single and bulk emails in Spring Boot.

If you are a Gradle user, open the build.gradle file in the root folder of your project. Add the following line in the dependencies object:

implementation 'com.sendgrid:sendgrid-java:4.9.3'

Otherwise, if you are a Maven user, navigate to the pom.xml file in the root folder of your project. Open it and add the following lines to the dependencies section:

<dependency>
    <groupId>com.sendgrid</groupId>
    <artifactId>sendgrid-java</artifactId>
    <version>4.9.3</version>
</dependency>

You just added the Twilio SendGrid Java Helper Library to your project’s dependencies.

Always prefer the latest version of the Twilio SendGrid Java Helper Library. At the time of writing, the latest version is 4.9.3. Since new versions are released frequently, keep an eye on the Twilio SendGrid Java Helper Library Maven Repository page.

After saving the project's dependency file, IntelliJ IDEA will show the Gradle/Maven reload button below:

The Gradle dependency update button

Click the button to install the Twilio SendGrid Java Helper Library.

Prepare your project to use SendGrid

First, initialize application.properties file under the /resources folder as below:

spring.sendgrid.api-key="<YOUR_SENDGRID_API>"
twilio.sendgrid.from-email="<YOUR_EMAIL>"

Replace the placeholder strings with your SendGrid API key and verified sender email. Note that you can configure these two fields to be read from environment variables.

When Spring Boot detects the spring.sendgrid.api-key setting, it will automatically set up a SendGrid bean. This class coming from the Twilio SendGrid Java Helper Library allows you to perform SendGrid API calls to programmatically send emails.

Time to structure your Spring Boot project.

In Spring Boot, services are classes marked with the @Service annotation that contains the business logic of your application. Create a package to group all your services.

In IntelliJ IDEA, right-click the com.twilio.bulkemails package on the left, select New > Package, type "services," and press the Enter key. The service package represents the service layer of your Spring Boot application.

In the service package, initialize an EmailService.java file as below:

package com.twilio.bulkemails.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.sendgrid.SendGrid;

@Service
public class EmailService {
    private final SendGrid sendGrid;
    private final String fromEmail;

    public EmailService(
            // get the SendGrid bean automatically created by Spring Boot
            @Autowired SendGrid sendGrid,
            // read your email to use as sender from application.properties
            @Value("${twilio.sendgrid.from-email}") String fromEmail
    ) {
        this.sendGrid = sendGrid;
        this.fromEmail = fromEmail;
    }

   // methods to send single and bulk emails...
}

This class will contain the business logic methods to send emails with SendGrid in Java. The SendGrid object gets initialized by Spring Boot, while fromEmail is read from twilio.sendgrid.from-email in application.properties through the @Value annotation.

Next, add a controllers package within the com.twilio.bulkemails package. This is the controller layer of your application and will contain all your @RestController files. In Spring Boot, a controller is a class where you define the API endpoints exposed by the backend.

In the controllers package, create a new Java class called EmailController.java and initialize it as follows:

package com.twilio.bulkemails.controllers;

import com.twilio.bulkemails.services.EmailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/v1/emails")
public class EmailController {
    private final EmailService emailService;

    public EmailController(
            @Autowired EmailService emailService
    ) {
        this.emailService = emailService;
    }

    // API endpoints to send single and bulk emails...
}

This file will contain all API endpoints to send bulk emails in three different ways. Each of these APIs will rely on the business logic methods from the underlying service layer.

Send Bulk Emails in Spring Boot via API

Assume your goal is to inform a large audience via email. Twilio SendGrid offers many ways to achieve that. Let's explore three different approaches you can take to send bulk emails in Spring Boot.

If you prefer to jump right into the code rather than build the Spring Boot application as you read, clone the GitHub repository that supports the article with this command:

git clone https://github.com/Tonel/twilio-sendgrid-bulk-emails

Follow this step-by-step tutorial to learn how to achieve the same result!

Send a single email many times

The most basic approach to bulk emails involves creating an API to send a single email and call it as many times as you need. Specifically, you have to call it once for each contact you want to reach via email. Let’s take a look at how to implement such an API in Spring Boot.

Add the sendSingleEmail() method below to EmailService.java file:

public void sendSingleEmail(String toEmail) {
    // specify the email details
    Email from = new Email(this.fromEmail);
    String subject = "Hello, World!";
    Email to = new Email(toEmail);
    Content content = new Content("text/plain", "Welcome to the Twilio SendGrid world!");

    // initialize the Mail helper class
    Mail mail = new Mail(from, subject, to, content);

    // send the single email
    sendEmail(mail);
}

sendSingleEmail() uses the SendGrid Mail helper class to instantiate an Email object containing a predefined message. Then, it uses it to email the recipient read from the toEmail parameter through sendEmail().

sendEmail() is a private method inside EmailService.java that encapsulates the logic of sending an email with the SendGrid mail/send API. Define it in EmailService.java as follows:

 

private void sendEmail(Mail mail) {
    try {
        // set the SendGrid API endpoint details as described
        // in the doc (https://docs.sendgrid.com/api-reference/mail-send/mail-send)
        Request request = new Request();
        request.setMethod(Method.POST);
        request.setEndpoint("mail/send");
        request.setBody(mail.build());

        // perform the request and send the email
        Response response = sendGrid.api(request);
        int statusCode = response.getStatusCode();
        // if the status code is not 2xx
        if (statusCode < 200 || statusCode >= 300) {
            throw new RuntimeException(response.getBody());
        }
    } catch (IOException e) {
        // log the error message in case of network failures
        e.printStackTrace();
        throw new RuntimeException(e.getMessage());
    }
}

sendEmail() uses the SendGrid instance to call the mail/send API. In case of a network error or a non-2xx response, it raises an exception. For better error handling, you should replace RuntimeException with a custom or more accurate exception.

Most of the classes used above come from the Twilio SendGrid Java Helper Library. Import them by adding the following lines on top of your EmailService.java file:

import com.sendgrid.helpers.mail.Mail;
import com.sendgrid.helpers.mail.objects.Content;
import com.sendgrid.helpers.mail.objects.Email;
import com.sendgrid.Method;
import com.sendgrid.Request;
import com.sendgrid.Response;
import java.io.IOException;

Next, define an API endpoint that calls the business logic sendSingleEmail() method. Add the following method to EmailController.java:

@PostMapping("/sendSingleEmail")
public ResponseEntity<String> sendSingleEmail(
        @RequestBody String to
) {
    // send single email
    emailService.sendSingleEmail(to);

    return ResponseEntity.ok("Single email sent successfully!");
}

This defines a /api/v1/email/sendSingleEmail POST API endpoint to programmatically send an email in Spring Boot. It reads the recipient’s email address from the request body and passes it to sendSingleEmail() to send an email to the desired contact.

Time to test the API endpoint!

In IntelliJ IDEA, click the Run button to launch your Spring Boot app. Wait for Spring Boot to start and then open your terminal.

If you are a Linux or macOS user, test the API with the command below:

curl -X POST -H "Content-Type: application/json" -d '"to_email@example.com"' http://localhost:8080/api/v1/emails/sendSingleEmail

Or if you are a Windows user, execute the following PowerShell command:

Invoke-WebRequest -Uri http://localhost:8080/api/v1/emails/sendSingleEmail -Method POST -Body '"to_email@example.com"' -ContentType 'application/json'

This performs a POST request to the /sendSingleEmail endpoint on the local development server. Please remember to change the email address specified in the body with your emails to avoid sending SPAM messages.

Great! You should receive an email containing the message specified in the code.

You could now call the API multiple times to notify as many users as you want. However, that is not a good approach for at least three reasons:

  1. Complex error handling: If you want to make this process reliable, you need to implement retry logic to protect against network and your or SendGrid’s API failures.
  2. Network overhead: Each call to your API takes a network trip, which requires sending packages and waiting for a response.
  3. Slow performance: Sending emails sequentially takes time and means that your contacts will not receive the message at the same time.

In short, this approach is fine if your target audience is small and it is not too important if someone does not receive the email. Let’s move on to a better approach.

Send emails in parallel

Instead of sending many emails sequentially, another approach for implementing bulk emails is to send several emails in parallel.

Implementing this approach takes only a few lines of code. Add the sendMultipleEmails() method to EmailService.java:

public void sendMultipleEmails(List<String> tos) {
    // iterate over the list of destination emails
    // and email each of them
    tos.parallelStream().forEach(this::sendSingleEmail);
}

Thanks to the parallelStream() method, you can iterate the list of recipients received as input in parallel. This means sending emails to multiple users simultaneously.

Define a corresponding API endpoint in EmailController.java by defining this method:

@PostMapping("/sendMultipleEmails")
public ResponseEntity<String> sendMultipleEmails(
        @RequestBody List<String> tos
) {
    // send the same email to multiple recipients
    emailService.sendMultipleEmails(tos);

    return ResponseEntity.ok("Multiple emails sent successfully!");
}

The /api/v1/email/sendMultipleEmail POST API endpoint takes a list of email addresses and sends an email message to all of them.

After starting the application, you can test the new endpoint by specifying an array of email addresses in the JSON body of the request.

On macOS and Linux, use the command below to test the API:

curl -X POST -H "Content-Type: application/json" -d '["to_email_1@example.com", "to_email_2@example.com"]' http://localhost:8080/api/v1/emails/sendMultipleEmails

On Windows:

Invoke-WebRequest -Uri http://localhost:8080/api/v1/emails/sendMultipleEmails -Method POST -Body '["to_email_1@example.com", "to_email_2@example.com"]' -ContentType 'application/json'

Again, make sure to replace the email addresses in the body with emails you own.

Yet, even that approach has some big limitations:

  • It drains your SendGrid credits: You are still calling one SendGrid API per recipient, which means a lot of API calls.
  • It may trigger the SendGrid rate limiting protection: You might receive a 429 response from the SendGrid API because of too many requests in a short amount of time.

Time to see the definitive approach to bulk emails in SendGrid!

Send a single email to multiple recipients

A better approach to bulk emails is to use the SendGrid Personalization feature to send a single email to many users by specifying multiple ‘to,” ”cc,” or “bcc” recipients.

In EmailService.java, add the sendBulkEmails() method below that takes advantage of the Personalization SendGrid class:

public void sendBulkEmails(List<String> tos) {
    // specify the email details
    Mail mail = new Mail();
    mail.setFrom(new Email(this.fromEmail));
    mail.setSubject("[BULK] Hello, World!");
    mail.addContent(new Content("text/html", "Welcome to the Twilio SendGrid world where you can send <strong>bulk emails</strong>!"));

    // add the multiple recipients to the email
    Personalization personalization = new Personalization();
    tos.forEach(to -> {
        // add each destination email address to the BCC
        // field of the email
        personalization.addBcc(new Email(to));
    });
    mail.addPersonalization(personalization);

    // send the bulk email
    sendEmail(mail);
}

In SendGrid, personalizations allow you to identify who should receive the email as well as details on how you want the email to be handled. To avoid disclosing all addresses the email will be sent to, you should prefer "bcc" to "cc" and "to" recipients.

When adding an email address to the “bcc” field with the addBcc() method, a copy of the message will be sent to that recipient but their name will not be visible to other recipients.

To make this method work, you will need to add the following imports on top of EmailService.java:

import com.sendgrid.helpers.mail.objects.Personalization;

SendGrid supports both plain text and HTML email content. You can also select dynamic templates and fill them out with the right data in your code. Explore the docs to learn more about dynamic templates.

All that remains is to define an API endpoint and test it. Add the method below to EmailController.java:

@PostMapping("/sendBulkEmails")
public ResponseEntity<String> sendBulkEmails(
        @RequestBody List<String> tos
) {
    // send bulk emails
    emailService.sendBulkEmails(tos);

    return ResponseEntity.ok("Bulk emails sent successfully!");
}

Run the Spring Boot Java app in IntelliJ and open the terminal.

On Linux or macOS, test the API with:

curl -X POST -H "Content-Type: application/json" -d '["to_email_1@example.com", "to_email_2@example.com"]' http://localhost:8080/api/v1/emails/sendBulkEmails

On Windows, use:

Invoke-WebRequest -Uri http://localhost:8080/api/v1/emails/sendBulkEmails -Method POST -Body '["to_email_1@example.com", "to_email_2@example.com"]' -ContentType 'application/json'

This command will call the /api/v1/emails/sendBulkEmail POST API and send bulk emails through your new emailing service.

Do not forget to replace the email addresses with emails you control before launching the local request.

Keep in mind that due to Twilio SendGrid’s limitations, you may still run into some errors. The total number of recipients in the “to,” “cc,” and “bcc” fields must be no more than 1000.

Congrats! You just learned how to implement an API to send bulk email messages in Spring Boot!

What's next for using the Twilio SendGrid Email API in Java?

In this step-by-step tutorial, you explored different approaches to sending bulk emails in Twilio. In particular, you saw how to use the Twilio SendGrid Java Helper Library in Spring Boot to build APIs to notify several contacts via email. This took only a handful of lines of code. That is possible thanks to the Twilio SendGrid API, which enables you to send bulk email messages with no effort.

All that remains is to make the application more complex and robust. For example, you could retrieve the contact list from an API or with a query to the database, use dynamic templates, and receive the email content as input.

Antonello Zanini is a CEO, technical writer, and software engineer but prefers to call himself a Technology Bishop. Spreading knowledge through writing is his mission. He can be reached on LinkedIn or at antonello [at] writech.run.