How to send bulk emails using Spring Batch
Imagine you had an e-commerce application where you’re implementing microservices architecture. Well, one of those microservices could be an email sending application where its only role is to send emails to the customers.
In this example, we’ll be sending emails to all customers who have placed an order which has been confirmed and is ready for shipping.
We’ll take a look at how to send 500+ emails and how to configure a batch job, add a step and configure a reader, processor, and writer. You can find all the code in this git repository together with a test database: https://github.com/mamin11/batch_email_sender
I’ll be using MailHog as an email server. It’s free and easy to set up. I have mine running on docker. You can use this link to find more information on how to set up yours. https://hub.docker.com/r/mailhog/mailhog/
The first thing we’ll need to do is head over to https://start.spring.io/ and create a new application. We’ll need the following dependencies:
- Spring batch
- MySQL driver
- spring data JPA
- java mail sender
- Lombok — optional
Once you’ve done the above, download your application and open it in IntelliJ
We’ll add the following properties to connect to our databases and email server
Configuring A Job
First, let’s create a class where we’ll configure our batch process. I’ve called mine BatchConfig. Then add these two annotations: @EnableBatchProcessing and @Configuration This is what the class looks like for now.
Then in this class, we’ll autowire the following to create a job and steps.
Now we can create our job. I’ve called mine emailSenderJob which has the same value as the variable JOB_NAME but pick any name that you like. I’ve also added a random integer to the job name.
Then we start and call emailSenderStep which looks like this:
Using a stepBuilderFactory we autowired earlier, we first give our step a name by passing the variable STEP_NAME to get().
In chunk, we define how much data we want to process at a time, in this case, 100. Also, we define what datatype we consume and return from this step, in this case, OrdersDTO.
Then we have a reader, a processor, and a writer, each is a bean.
In the reader, we’ll read all the data from the orders table where emails have not yet been sent. We’ll use JdbcCursorItemReaderBuilder and a SQL query to fetch the data.
The datasource we autowired earlier will let us connect to the database. The connection properties, we defined in application.properties.
We’re also using a row mapper to convert the data we fetch from the database into java objects. With this, we’ll have a list of OrdersDTO which each will then be passed to our processor.
Here’s what the row mapper looks like. We map each column to its respective property in OrdersDTO.
In the processor, we’ll send emails for each order. We return a new instance of OrderProcessor where have the logic to send emails.
We have an email sending class which we autowire. We pass the customer email and the message we want to send to our emailSenderService.
Email Sender service class
Email sender service is a component class to basically send emails. We use JavaMailSender.
Finally, we have a writer where we’ll save the updated data, ie the email_sent column has been set to true.