Part of #722, step 3 (phase 2), following bounded async submission. Add total-send budgets and cancellation that reaches queued work, pool waits and actual SMTP I/O while retaining accepted, known-unsent and ambiguous outcomes. The accepted API direction is MailSend with getCompletion() and secondary getCancellation().request(), without more send overloads. A cancellation request never recalls accepted mail. Preserve observer-after-cleanup ordering, lazy batches, caller-owned resources and truthful custom-mailer capability. First prove safe interruption through supported provider hooks; if Angus cannot provide it without reflection or global mutable state, define the necessary provider/upstream seam instead of advertising future-only cancellation. Follow the root API expansion and coding guides, add fault-boundary and pooled-concurrency tests, and document stopped background/bulk-mail jobs. Leave implementation for review before commit.
Provider gate
Queue controls are being implemented separately in #725. In-flight cancellation is not implemented yet: cancelling a CompletableFuture does not stop SMTP, and Angus SMTPTransport.close() waits behind a send holding the transport monitor. A late request can therefore still be followed by successful SMTP acceptance.
Before exposing MailSend, we need a provider-owned, monitor-independent abort hook covering connection setup and TLS as well as sending, bound to the current attempt so it cannot affect a reused pooled connection. Pool waiting/allocation must cooperate, and the terminal receipt must retain final acceptance or post-DATA uncertainty. Caller-owned providers and CustomMailer callbacks also need an honest supported/unsupported boundary.
The next decision is an upstream Angus/pool hook or a separately reviewed socket-owning provider integration. Socket-factory/custom-provider alternatives are not ruled out by the current characterization, but must preserve Session, TLS, proxy, and lease ownership semantics. The step's stop condition applies; no deadline/cancellation return-type change is exposed yet. The detailed continuation is recorded in step 3 of the root SMTP robustness plan.
Part of #722, step 3 (phase 2), following bounded async submission. Add total-send budgets and cancellation that reaches queued work, pool waits and actual SMTP I/O while retaining accepted, known-unsent and ambiguous outcomes. The accepted API direction is MailSend with getCompletion() and secondary getCancellation().request(), without more send overloads. A cancellation request never recalls accepted mail. Preserve observer-after-cleanup ordering, lazy batches, caller-owned resources and truthful custom-mailer capability. First prove safe interruption through supported provider hooks; if Angus cannot provide it without reflection or global mutable state, define the necessary provider/upstream seam instead of advertising future-only cancellation. Follow the root API expansion and coding guides, add fault-boundary and pooled-concurrency tests, and document stopped background/bulk-mail jobs. Leave implementation for review before commit.
Provider gate
Queue controls are being implemented separately in #725. In-flight cancellation is not implemented yet: cancelling a CompletableFuture does not stop SMTP, and Angus SMTPTransport.close() waits behind a send holding the transport monitor. A late request can therefore still be followed by successful SMTP acceptance.
Before exposing MailSend, we need a provider-owned, monitor-independent abort hook covering connection setup and TLS as well as sending, bound to the current attempt so it cannot affect a reused pooled connection. Pool waiting/allocation must cooperate, and the terminal receipt must retain final acceptance or post-DATA uncertainty. Caller-owned providers and CustomMailer callbacks also need an honest supported/unsupported boundary.
The next decision is an upstream Angus/pool hook or a separately reviewed socket-owning provider integration. Socket-factory/custom-provider alternatives are not ruled out by the current characterization, but must preserve Session, TLS, proxy, and lease ownership semantics. The step's stop condition applies; no deadline/cancellation return-type change is exposed yet. The detailed continuation is recorded in step 3 of the root SMTP robustness plan.