Skip to content

Expose SMTP submission receipts with server response details #654

Description

@bbottema

Problem

Simple Java Mail currently reports send success/failure through CompletableFuture<Void> and exceptions. That tells callers whether the send path completed, but it does not expose the SMTP server's final submission response, such as a 250 ... queued as ... message or provider-specific queue id.

Angus Mail exposes this at the transport level via SMTPTransport#getLastReturnCode() and SMTPTransport#getLastServerResponse(), but Simple Java Mail intentionally hides transport ownership behind higher-level APIs.

Concept

Expose a high-level submission receipt that represents SMTP server acceptance of the submitted message, not final delivery to the recipient mailbox.

Possible API shape:

CompletableFuture<MailSubmissionReceipt> sendMailAndGetReceipt(Email email);
CompletableFuture<MailSubmissionReceipt> sendMailAndGetReceipt(Email email, boolean async);

Possible model shape:

public final class MailSubmissionReceipt {
    String getEmailId();
    Optional<SmtpServerResponse> getSmtpResponse();
    boolean isAcceptedByServer();
    Instant getSubmittedAt();
}

public final class SmtpServerResponse {
    int getReturnCode();
    String getResponse();
}

For the open-connection API, consider adding a receipt-returning method to the scoped sender:

mailer.withOpenConnection(sender -> {
    MailSubmissionReceipt receipt = sender.sendMailAndGetReceipt(email);
    auditLog.store(receipt.getSmtpResponse());
});

Implementation Notes

  • Capture the response immediately after Transport#sendMessage(...), before closing or releasing the transport.
  • When the actual transport is Angus SMTPTransport, populate return code and server response.
  • Define behavior for non-SMTP/custom mailer/transport-mode-logging-only paths, likely by returning an empty Optional<SmtpServerResponse> or documenting that no SMTP response exists.
  • Keep existing sendMail(...) methods as convenience methods returning CompletableFuture<Void>.
  • Avoid naming this DeliveryResult; this is submission/acceptance, while actual delivery remains asynchronous and belongs to DSN/bounce handling.

Acceptance Criteria

  • Callers can send one email and inspect the SMTP server submission response when available.
  • Existing sendMail(...) behavior remains source-compatible.
  • The open-connection sender can expose the same receipt data without exposing raw Transport ownership.
  • Documentation clearly distinguishes SMTP submission acceptance from final recipient delivery and from Delivery Status Notification behavior.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions