flowable/flowable-engine · error · FlowableMailException
Failed to create multi part email
Error message
Failed to create multi part email
What it means
For emails that are not text-only (html present or attachments present), setContent() builds content via createMultiPartContent and assigns it with mimeMessage.setContent(...). A MessagingException from that call is wrapped as FlowableMailException "Failed to create multi part email". It indicates the MIME multipart structure could not be attached to the message.
Solutions
- Inspect the nested MessagingException cause for the failing MIME part
- Verify attachment DataSources are readable and have valid names/content types
- Ensure a single consistent jakarta.mail implementation is on the classpath
- Test with a minimal HTML-only email to isolate whether attachments are the cause
Example fix
// before: custom DataSource returning null content type
new DataSource() { public String getContentType() { return null; } ... }
// after
new DataSource() { public String getContentType() { return "application/octet-stream"; } ... } Defensive patterns
Strategy: try-catch
Validate before calling
attachments.forEach(a -> {
if (a.getContentType() == null || a.getName() == null)
throw new IllegalArgumentException("Attachment missing name/content-type");
}); Try / catch
try {
mailClient.send(mailMessage);
} catch (FlowableMailException e) {
if (e.getMessage().contains("Failed to create multi part email")) {
log.error("Multipart assembly failed; check attachments and jakarta.mail version", e.getCause());
}
} Prevention
- Give every attachment DataSource a valid name and content type
- Avoid mixing javax.mail and jakarta.mail artifacts
- Smoke-test HTML+attachment sends after upgrading Flowable
When it happens
Trigger: Sending an HTML email (optionally with attachments) where mimeMessage.setContent(multipart) or the internal multipart assembly throws MessagingException — e.g. corrupted part structure or provider failure.
Common situations: Large or malformed attachments failing during DataHandler wiring; Jakarta Mail provider incompatibilities; mixing incompatible jakarta.mail versions where multipart handling differs.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- Failed to add body part
- Could not create text-only email
- Failed to set send date
- Attachment content is required.
- Cannot create multi part entity
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/52cdc687e3ae4d5e.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-mail/src/main/java/org/flowable/mail/common/impl/jakarta/mail/JakartaMailFlowableMailClient.java:270
protected void setContent(MimeMessage mimeMessage, MailMessage message, String charset) {
String text = message.getPlainContent();
String html = message.getHtmlContent();
Collection<DataSource> attachments = message.getAttachments();
boolean attachmentsExists = attachments != null && !attachments.isEmpty();
if (html == null && text == null) {
throw new FlowableIllegalArgumentException("'html' or 'text' is required to be defined when sending an email");
}
if (html == null && !attachmentsExists) {
try {
mimeMessage.setText(text, charset);
} catch (MessagingException e) {
throw new FlowableMailException("Could not create text-only email", e);
}
} else {
try {
mimeMessage.setContent(createMultiPartContent(text, html, charset, attachments));
} catch (MessagingException e) {
throw new FlowableMailException("Failed to create multi part email", e);
}
}
}
protected MimeMultipart createMultiPartContent(String text, String html, String charset, Collection<DataSource> attachments) throws MessagingException {
boolean attachmentsExists = attachments != null && !attachments.isEmpty();
MimeMultipart rootContainer = new MimeMultipart();
MimeMultipart bodyContainer = rootContainer;
rootContainer.setSubType("mixed");
if (StringUtils.isNotEmpty(text) && StringUtils.isNotEmpty(html)) {
if (attachmentsExists) {
// If both HTML and TEXT bodies are provided, create an alternative
// container and add it to the root container
bodyContainer = new MimeMultipart("alternative");
MimeBodyPart bodyPart = new MimeBodyPart();View on GitHub (pinned to d6d39ce1c6)