Maintain

Migrating to 9.0

Breaking changes and migration guidance for Simple Java Mail 9.0.

§

Recipient methods were replaced

Impact: Calls to the old to(...), cc(...), bcc(...), and related recipient overloads no longer compile.

Build recipients explicitly with RecipientBuilder, set their recipient type, and add them through withRecipients(...).

A RecipientBuilder always produces exactly one Recipient. Pass one RFC 2822 address to withAddress(...), optionally including a display name such as Alice <alice@example.com>. It does not split comma- or semicolon-delimited address lists.

// Before 9.0.0:
Email email = EmailBuilder.startingBlank()
    .from("me@example.com")
    .to("Alice", "alice@example.com")
    .cc("audit@example.com")
    .withPlainText("Hello")
    .buildEmail();

// Since 9.0.0:
Email email = EmailBuilder.startingBlank()
    .from("me@example.com")
    .withRecipients(
        new RecipientBuilder()
            .withName("Alice")
            .withAddress("alice@example.com")
            .withType(Message.RecipientType.TO)
            .build(),
        new RecipientBuilder()
            .withAddress("audit@example.com")
            .withType(Message.RecipientType.CC)
            .build())
    .withPlainText("Hello")
    .buildEmail();

For several recipients, use RecipientsBuilder. Each String argument may contain one address or a comma- or semicolon-delimited list; every parsed address becomes a separate Recipient:

Collection<Recipient> recipients = new RecipientsBuilder()
    .withRecipientsWithDefaultName(
        null,
        Message.RecipientType.TO,
        "alice@example.com,bob@example.com",
        "Carol <carol@example.com>;dave@example.com")
    .buildRecipients();

Email email = EmailBuilder.startingBlank()
    .from("me@example.com")
    .withRecipients(recipients)
    .withPlainText("Hello")
    .buildEmail();

For an existing Recipient or collection, replace to(...), cc(...), or bcc(...) with withRecipients(...) and make sure each recipient already carries the intended type.

See the dedicated recipient builder examples for the current API.

§

Outlook InputStream conversion result

Impact: The InputStream overloads of outlookMsgToEmailBuilder(...) are deprecated and return an internal wrapper type.

Use outlookMsgToEmailBuilderWithOutlookData(...) when you need both the email builder and source .msg metadata. If you only need the converted email, the existing outlookMsgToEmail(...) method remains the shorter route.

// Before 9.0.0:
EmailFromOutlookMessage result =
    EmailConverter.outlookMsgToEmailBuilder(msgInputStream);
Email email = result.getEmailBuilder().buildEmail();

// Since 9.0.0:
OutlookEmailConversionResult result =
    EmailConverter.outlookMsgToEmailBuilderWithOutlookData(msgInputStream);
Email email = result.buildEmail();
OutlookMessageData sourceData = result.getOutlookMessageData();
§

Generated attachment Content-ID values changed

Impact: Raw MIME tests or integrations that inspect automatically generated attachment Content-ID values may need updating.

An attachment without an explicit Content-ID now receives an opaque value in the form sjm-...@simplejavamail.generated. Earlier versions derived the value from the attachment name and a UUID. Embedded images still use their resource name when no separate Content-ID is supplied.

// Before 9.0.0:
Content-ID: <report.pdf@...>

// Since 9.0.0:
Content-ID: <sjm-...@simplejavamail.generated>

Do not depend on a generated value. If another system requires a stable Content-ID, supply it explicitly:

emailBuilder.withAttachment(
    "report.pdf",
    reportData,
    null,
    null,
    "stable-report-id");
§

Cluster pool defaults are scoped per cluster

Impact: Applications with more than one cluster key no longer share what effectively behaved like one JVM-wide set of pool defaults.

The first Mailer registered for each cluster key now defines that cluster's pool size, claim timeout, expiry, and load-balancing strategy. If several clusters previously relied on settings supplied for only one of them, repeat the intended settings on the first Mailer registered under every key.

Mailer ordersMailer = MailerBuilder
    .withSMTPServer("orders-smtp.example.com", 587, "user", "password")
    .withClusterKey(ordersCluster)
    .withConnectionPoolMaxSize(3)
    .withConnectionPoolLoadBalancingStrategy(LoadBalancingStrategy.RANDOM_ACCESS)
    .buildMailer();

Property-file and Spring configurations can define the same settings per cluster under simplejavamail.defaults.connectionpool.clusters.*. See clustering configuration for the complete forms.

§

Async mailer defaults apply to testConnection

Impact: On a Mailer configured with async(), no-argument testConnection() no longer blocks.

The no-argument method now follows the Mailer's asynchronous default, just like sendMail(...). Replace it with testConnection(false) wherever a blocking startup or health check is required.

§

Resource filenames moved out of Content-Type filename

Impact: Code or tests that inspect generated attachment and embedded-image MIME headers may need updating.

Simple Java Mail no longer adds the non-standard filename parameter to Content-Type. The filename remains in the standard Content-Disposition parameter, while Content-Type keeps the legacy-compatible name parameter.

// Before 9.0.0:
Content-Type: application/pdf; filename=report.pdf; name=report.pdf
Content-Disposition: attachment; filename=report.pdf

// Since 9.0.0:
Content-Type: application/pdf; name=report.pdf
Content-Disposition: attachment; filename=report.pdf