spring-projects / spring-projects/spring-framework
Add fluent MimeMessage builder as a modern alternative to MimeMessageHelper
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 60.2k
- Forks
- 38.8k
- Avg merge
- 5d 2h
- Merged PRs (30d)
- 27
Description
What I'd like
A fluent way to build MIME messages without the ceremony that MimeMessageHelper requires:
var message = MimeMessageBuilder.builder()
.from("notification@example.com", "App Name")
.to(List.of("recipient@example.com"))
.cc(ccList)
.subject("Hello")
.text("Plain text fallback")
.html("<h1>Hello</h1>")
.attachment("report.pdf", bytes, "application/pdf")
.header("X-Custom", "value")
.build();
javaMailSender.send(message);
What we do today
Every project I've seen (including ours) ends up with something like this:
javaMailSender.send(mimeMessage -> {
var multipart = hasText(req.getHtml()) || !req.getAttachments().isEmpty();
var helper = new MimeMessageHelper(mimeMessage, multipart, StandardCharsets.UTF_8.name());
helper.setTo(req.getTo().toArray(String[]::new));
if (req.getCc() != null) {
helper.setCc(req.getCc().toArray(String[]::new));
}
if (req.getBcc() != null) {
helper.setBcc(req.getBcc().toArray(String[]::new));
}
if (hasText(req.getHtml()) && hasText(req.getText())) {
helper.setText(req.getText(), req.getHtml());
} else if (hasText(req.getHtml())) {
helper.setText(req.getHtml(), true);
} else {
helper.setText(req.getText());
}
if (hasText(req.getFromName())) {
helper.setFrom(req.getFrom(), req.getFromName());
} else {
helper.setFrom(req.getFrom());
}
if (hasText(req.getSubject())) helper.setSubject(req.getSubject());
if (hasText(req.getReplyTo())) helper.setReplyTo(req.getReplyTo());
// attachments...
});
It's not terrible, but it's a lot of defensive code for something that should be straightforward. The main annoyances:
- You have to figure out the
multipartflag yourself before you even start setCc(null)throws, so every optional field needs a null check- Lists need
toArray(String[]::new)every time - Text vs HTML vs both requires a three-way branch
- None of this is really "our" logic — it's just wiring
Suggested behavior
- Multipart mode figured out automatically from whether there's HTML/attachments
- Null or empty optional fields just get ignored (no exception)
- Takes collections directly
- If both
.text()and.html()are called, it does the right thing (multipart/alternative) - UTF-8 by default
I think of it as the same kind of improvement RestClient brought over RestTemplate — the imperative API is still there, but the common case gets much nicer.
Happy to take a stab at a PR if there's interest.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the existing MimeMessageHelper usage and the RestClient/RestTemplate relationship described in the issue. Define the builder's scope around the shown from, recipient, subject, text, HTML, attachment, and header operations, then verify that UTF-8 defaults, optional-field handling, multipart selection, and combined text/HTML behavior are covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- backend, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100