2026-07-15

How to send an email to multiple recipients in Spring

Stefan Bogdanescu

Stefan Bogdanescu

Founder & Senior Architect

How to send an email to multiple recipients in Spring

How to Send Emails to Multiple Recipients in Spring: A Deep Dive into JavaMail

As senior developers, we often deal with backend operations that require precise handling of data, especially when interfacing with external services like email providers. One common stumbling block is sending a single message to multiple recipients—an operation that seems straightforward but can hide subtle issues depending on how the underlying library (in this case, JavaMail) interprets array inputs.

Today, we are dissecting a specific scenario where developers encounter an issue: attempting to send an email using a String[] array for recipients only results in the message being delivered to the last address in the list. We will explore why this happens and provide a robust, production-ready solution.

Understanding the Problem: Why Only the Last Email Gets It

The issue stems from how the MimeMessageHelper interacts with the input parameters. When you call methods like helper.setTo(to), if the underlying library is designed to handle single recipient sets efficiently, it might be defaulting to processing only the last element when provided with an array of strings. For robust multi-recipient handling, we need to explicitly instruct the mail client which addresses should be included in the distribution list.

In essence, providing a raw array doesn't always trigger the necessary iteration required for true mass distribution within the context of the MimeMessageHelper. We need to manually iterate through the recipients and add each one individually to ensure every address is correctly registered as a recipient.

The Solution: Iterating for Reliable Multi-Recipient Delivery

To guarantee that an email is sent successfully to every address in the provided array, we must move beyond simple assignment and implement an explicit loop. We will iterate over the to array and use the appropriate method to add each recipient to the message structure.

The key change involves replacing the single call to helper.setTo(to) with a loop that iterates over the array and uses methods like addRecipient() or directly manipulating the To header if necessary, ensuring explicit instruction for every address.

Refactored Code Example

Here is how we can refactor your method to correctly handle multiple recipients:

import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
import java.util.Iterator;
import java.util.List;

public void sendMail(String from, String[] to, String subject, String msg, List attachments) throws MessagingException, IOException {

    // Creating message  
    sender.setHost("smtp.gmail.com");
    MimeMessage mimeMsg = sender.createMimeMessage();
    MimeMessageHelper helper = new MimeMessageHelper(mimeMsg, true);
    Properties props = new Properties();
    props.put("mail.smtp.starttls.enable", "true");
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.port", "425");

    Session session = Session.getDefaultInstance(props, null);

    helper.setFrom(from);

    // *** FIX APPLIED HERE: Iterating to add all recipients ***
    for (String recipient : to) {
        helper.addRecipient(Message.RecipientType.TO, new InternetAddress(recipient));
    }

    helper.setSubject(subject);
    helper.setText(msg + "<html xmlns='http://www.w3.org/1999/xhtml'><body style='font-family: sans-serif;'><h1>Hi Welcome!</h1></body></html>", true);

    // Handling Attachments
    Iterator it = attachments.iterator();
    while (it.hasNext()) {
        FileSystemResource file = new FileSystemResource(new File((String) it.next()));
        helper.addAttachment(file.getFilename(), file);
    }

    // Sending message  
    sender.send(mimeMsg);
}

Best Practices for Robust Email Handling

When dealing with complex backend operations, especially those involving external communications, robustness is paramount. This principle—explicit instruction over implicit assumptions—is critical in software development.

  1. Explicit Recipient Management: As demonstrated above, always iterate when handling collections of recipients. Avoid relying on methods that might implicitly handle only the last item unless you have explicit documentation confirming this behavior for your specific JavaMail implementation.
  2. Error Handling: Always wrap external calls (like sender.send(mimeMsg)) in comprehensive try-catch blocks to manage potential SMTP errors, connection failures, or authentication issues. A well-structured API is essential; think about how clean APIs influence the architecture of your services, much like robust MVC patterns seen in frameworks like Laravel.
  3. Separation of Concerns: Keep the logic for constructing the message (headers, body, attachments) separate from the logic for sending it. This makes debugging easier and allows you to test the message assembly independently before hitting the network layer.

Conclusion

Sending emails to multiple recipients requires careful attention to the details of how recipient lists are constructed within the JavaMail framework. By replacing the simple array assignment with an explicit loop that calls addRecipient() for every address, we ensure that your application behaves predictably and reliably, regardless of the input size. Mastering these low-level interactions is what separates functional code from production-grade software.

Note: Blog content is currently available in English.

Tags:

Enhance your marketing setup with your own email marketing platform.

Join the growing number of SaaS platforms using Laravel Mail to offer email marketing solutions to their customers.