Skip to content

mail.sslPort required (and blank-unsafe) even when SSL disabled → config crash at send #12

@fupelaqu

Description

@fupelaqu

Summary

mail.sslPort / mail.ssl-port is required to be a valid Int even when SSL is disabled (sslEnabled = false). If MAIL_SSL_PORT resolves to an empty string, config load throws and the notification entity crashes at send time — so mail is never attempted, with a misleading error.

Observed error

When MAIL_SSL_ENABLED=false and MAIL_SSL_PORT is unset/blank (only the plaintext MAIL_PORT is provided):

com.typesafe.config.ConfigException$Generic:
  [notification.mail.ssl-port] ... ssl-port has type STRING value '' rather than int (32-bit integer)
    at app.softnetwork.notification.config.MailSettings.MailConfig(MailSettings.scala:13)
    at app.softnetwork.notification.spi.SimpleMailProvider.mailConfig(SimpleMailProvider.scala:21)
    at app.softnetwork.notification.spi.SimpleMailProvider.sendMail(SimpleMailProvider.scala:61)
  Caused by: java.lang.NumberFormatException: null
  Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0

The supervisor then stops the entity (StopSupervisor saw failure), so the email stays Pending/Undelivered and the caller just times out waiting for it.

Root cause

In reference.conf (notification-core):

mail {
  port      = 25
  port      = ${?MAIL_PORT}
  sslPort   = 465
  sslPort   = ${?MAIL_SSL_PORT}
  ssl-port  = ${notification.mail.sslPort}
  sslEnabled = true
  sslEnabled = ${?MAIL_SSL_ENABLED}
}

SimpleMailProvider always reads sslPort, regardless of sslEnabled:

commonsMail.setSmtpPort(mailConfig.port)
commonsMail.setSslSmtpPort(mailConfig.sslPort.toString)   // always read
commonsMail.setSSLOnConnect(mailConfig.sslEnabled)

Two problems:

  1. Blank env vars override the default. sslPort = ${?MAIL_SSL_PORT} substitutes when the variable is defined, including when it is the empty string. A MAIL_SSL_PORT="" (common in templated/compose/k8s env) overrides the 465 default with "", which then fails Int parsing. There's no blank-as-absent guard.
  2. sslPort is mandatory even when SSL is off. When sslEnabled = false the connection uses the plain port, yet sslPort must still parse as an Int or the whole MailConfig fails to load. A plaintext-only deployment (e.g. a dev/test SMTP sink like mailpit) is forced to also supply a dummy MAIL_SSL_PORT.

Impact

Any deployment pointing at a plaintext SMTP server with MAIL_SSL_ENABLED=false crashes config load unless a throwaway MAIL_SSL_PORT int is also set. The failure surfaces only at first send, as a config exception unrelated to the actual misconfiguration — hard to diagnose.

Suggested fixes (any one)

  • Treat blank env values as absent (e.g. read via an Option/nonBlank helper, falling back to the 465 default) for sslPort, port, and the other numeric mail settings.
  • Make sslPort optional / lazily required only when sslEnabled || startTLSEnabled, so plaintext-only configs don't need it.
  • In SimpleMailProvider, only call setSslSmtpPort(...) when sslEnabled is true.

Workaround (downstream)

Set MAIL_SSL_PORT to a valid int even when SSL is disabled:

MAIL_HOST: mailpit
MAIL_PORT: "1025"
MAIL_SSL_PORT: "1025"     # unused, but must parse as Int
MAIL_SSL_ENABLED: "false"
MAIL_START_TLS_ENABLED: "false"

Found while wiring the license-server compose-smoke e2e against a mailpit SMTP sink.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions