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.
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 a250 ... queued as ...message or provider-specific queue id.Angus Mail exposes this at the transport level via
SMTPTransport#getLastReturnCode()andSMTPTransport#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:
Possible model shape:
For the open-connection API, consider adding a receipt-returning method to the scoped sender:
Implementation Notes
Transport#sendMessage(...), before closing or releasing the transport.SMTPTransport, populate return code and server response.Optional<SmtpServerResponse>or documenting that no SMTP response exists.sendMail(...)methods as convenience methods returningCompletableFuture<Void>.DeliveryResult; this is submission/acceptance, while actual delivery remains asynchronous and belongs to DSN/bounce handling.Acceptance Criteria
sendMail(...)behavior remains source-compatible.Transportownership.