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

  1. Inspect the nested MessagingException cause for the failing MIME part
  2. Verify attachment DataSources are readable and have valid names/content types
  3. Ensure a single consistent jakarta.mail implementation is on the classpath
  4. 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

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


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)