Skip to content

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

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions