Skip to content

Add typed API for SMTP EHLO/HELO client hostname #653

Description

@bbottema

Problem

Corporate SMTP relays sometimes expect the client to present a stable, recognizable hostname in the SMTP EHLO/HELO command. Even when the relay does not enforce this, a deliberate client hostname is useful for corporate logging, tracing, audit trails, and SMTP-side diagnostics because it makes application traffic recognizable in mail-server logs.

Angus Mail supports this through provider properties such as mail.smtp.localhost / mail.smtps.localhost, but Simple Java Mail currently only exposes this through raw withProperty(...) usage.

This is easy to miss and easy to confuse with withLocalBindAddress(...), which controls the local socket source address instead of the SMTP protocol identity.

Proposed API

Add a typed mailer-level setting, for example:

MailerBuilder
    .withSMTPServer("smtp.corp.example", 587, user, pass)
    .withSmtpClientHostname("orders-service.prod.example.com")
    .buildMailer();

Also consider a corresponding clearer/reset API:

clearSmtpClientHostname()

Property/config support could use a name such as:

simplejavamail.smtp.clienthostname=orders-service.prod.example.com

Implementation Notes

  • Map to the correct Angus/Jakarta Mail property for the active transport strategy:
    • mail.smtp.localhost
    • mail.smtps.localhost
  • Document this as the hostname sent in EHLO/HELO.
  • Position the use case as SMTP client identity for relay policy, logging, tracing, auditability, and diagnostics.
  • Explicitly distinguish it from local bind address and envelope sender.
  • Validate or document expected hostname/FQDN shape if appropriate, but avoid over-validating legitimate corporate hostnames.

Acceptance Criteria

  • A typed API sets the EHLO/HELO client hostname without requiring raw property usage.
  • The setting works for both SMTP and SMTPS transport strategies where applicable.
  • Existing raw withProperty(...) behavior remains available.
  • Documentation explains the corporate relay/logging/tracing use case and the difference from withLocalBindAddress(...).

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions