flowable/flowable-engine · error · FlowableMailException

Could not create text-only email

Error message

Could not create text-only email

What it means

When the email is text-only (html is null and there are no attachments), setContent() calls mimeMessage.setText(text, charset). A MessagingException from setText is wrapped as FlowableMailException "Could not create text-only email". It means Jakarta Mail could not set the plain-text body on the freshly built MimeMessage.

Solutions

  1. Check the nested MessagingException cause for 'unsupported encoding' details
  2. Validate the charset value passed via the mail task / MailMessage (use standard names: UTF-8, ISO-8859-1)
  3. Ensure the JVM supports the charset (Charset.isSupported(charset))
  4. Use html content instead of plain text if the charset issue persists

Example fix

// before
<flowable:field name="text">
  <flowable:string>hello</flowable:string>
</flowable:field>
<flowable:field name="charSet"><flowable:string>utf_8</flowable:string></flowable:field>
// after
<flowable:field name="charSet"><flowable:string>UTF-8</flowable:string></flowable:field>
Defensive patterns

Strategy: validation

Validate before calling

if (charset != null && !java.nio.charset.Charset.isSupported(charset)) {
    throw new IllegalArgumentException("Unsupported charset: " + charset);
}

Try / catch

try {
    mailClient.send(mailMessage);
} catch (FlowableMailException e) {
    if (e.getMessage().contains("Could not create text-only email")) {
        log.error("setText failed — check charset in mail config", e.getCause());
    }
}

Prevention

When it happens

Trigger: Sending a plain-text-only email (no html, no attachments) where MimeMessage.setText(text, charset) throws — typically due to an unsupported charset name or a MessagingException from the MIME part internals.

Common situations: Passing an invalid/unknown charset string (e.g. a typo like 'utf_8' or a localized name not recognized by the JDK); misconfigured mail server charset settings feeding an invalid charset into the mail task.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/ccd4cf98dbfbf369. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-mail/src/main/java/org/flowable/mail/common/impl/jakarta/mail/JakartaMailFlowableMailClient.java:264

            }
        } catch (MessagingException e) {
            throw new FlowableMailException("Failed to set send date", e);
        }
    }

    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");

View on GitHub (pinned to d6d39ce1c6)