Skip to content

Expose structured delivery-status reports through Email #763

Closed

Description

@bbottema

Goal

Expose structured delivery-status report facts through the existing Email gateway. Applications convert incoming MIME/EML through the usual converter, then inspect Email.getDeliveryStatusReport(); no separate report-converter API.

Email notification = mail.converter().mimeMessageToEmailBuilder(incomingMessage).buildEmail();
DeliveryStatusReport report = notification.getDeliveryStatusReport();
if (report != null) {
    applicationWorkflow.accept(report);
}

Delivered design

  • Immutable, serializable core read contracts: DeliveryStatusReport, RecipientDeliveryReport, DeliveryAction, EnhancedStatusCode, ReportedRecipient, ReportedMailServer and DeliveryDiagnostic. Internal Lombok builders assemble the snapshots in the main module.
  • Interpret standard and internationalized delivery-status MIME structures after existing protection processing. Only the effective outer notification supplies a report; attached or forwarded reports are not promoted.
  • Expose ENVID, reporting server, ordered recipient occurrences, action, checked enhanced-status components, reported addresses, diagnostics and timestamps. Optional Recipient and SmtpServerResponse views avoid re-parsing familiar formats while preserving unfamiliar source values.
  • Read imperfect mail tolerantly: recover unambiguous formatting defects with warnings, retain completed facts after optional report extraction fails, and leave missing, contradictory or ambiguous facts unavailable. An interrupted block is not presented as complete. Required content reads, thread interruption and unexpected runtime failures retain their existing failure behavior.
  • Preserve copying, serialization, exact/protected source bytes and attachment behavior. Snapshots retain no live MIME objects or streams. Templates cannot manufacture received report metadata; replies and forwards do not inherit it.
  • Reports are received claims, not authenticated delivery proof, read receipts or automatic retry instructions. Ingestion, trust, correlation, persistence and business actions remain application-owned.
  • No new property, outgoing default/override/lock, CLI command, receiver, workflow engine or JSON dependency.

Acceptance

  • API/model/internal assembly and serialization coverage.
  • Standard/internationalized, malformed/duplicate/multiple-recipient fixtures and nested-report exclusion.
  • Existing S/MIME/OpenPGP and exact-message byte preservation, ordinary mail and attachment regressions.
  • Core/classpath/JPMS consumers, focused tests, actual JDK 11 and modern non-live verification. The verification record distinguishes full-reactor evidence from later focused refinements.
  • Feature examples/output, README/release history, architectural decisions and comparison companion. No migration entry for this additive behavior.
  • Production review accepted; selective code and website delivery approved.

Architecture and evidence

Related: #736, #738, #710, #723, #756. Comparison context: the SMTP-library research companion.

The integration/Strategic Patterns portfolio remains separately tracked under #764. Its pending code, documentation and Journal/case-study changes are not part of this delivery.

Implemented for unreleased 10.0.0 on the existing feature branches; this issue does not authorize a release or completion of #764.

Activity

  1. added this to the 10.0.0 milestone on Oct 16, 2026
  2. bbottema commented on Oct 16, 2026

    @bbottema
    OwnerAuthor

    Companion pattern-led Docker integration programme: #764. Implementation plan: docs/plans/763-delivery-status-reports.md. ADR 0008 will record the source-metadata boundary.

  3. moved this from Todo to In Progress in Simple Java Mail 10.0.0on Oct 16, 2026
  4. bbottema commented on Oct 16, 2026

    @bbottema
    OwnerAuthor

    Local implementation is ready for production-only review; nothing has been committed or pushed.

    The converted Email is the gateway, with core-only read contracts and internal main-module Lombok assembly:

    Email notification = mail.converter().mimeMessageToEmailBuilder(incomingMessage).buildEmail();
    DeliveryStatusReport report = notification.getDeliveryStatusReport();
    if (report != null) {
        System.out.println(report);
        for (RecipientDeliveryReport recipient : report.getRecipients()) {
            System.out.println(recipient.getAction() + " " + recipient.getStatusCode());
        }
    }

    Example summary: DeliveryStatusReport{recipients=3, delivered=1, delayed=1, failed=1, warnings=0}.

    Verification: full real-JDK-11 library lane passed; clean Java 21 reactor with Javadocs, regenerated CLI caches, API consumers and CLI/daemon checks passed (2,542 cases, zero failures/errors, one deliberately disabled manual performance test). Latest-source focused reruns passed too. Website: 89 tests, clean build and 5,009 internal links across 76 pages. Generated license headers were removed.

    Covered standard/international reports, malformed/conflicting fields, warning aggregation, source-only governance, copying/serialization, exact/protected bytes, and lazy unrelated attachment isolation. Reports remain received claims, not authenticated proof, a mutation of an earlier receipt, or automatic retry instructions.

    Local records: docs/research/763-delivery-status-verification.md, the saved #763 plan and ADR 0008's source-facts addendum. The comparison companion and website guidance are updated. #764 demonstrates application-owned integration rather than adding an SJM workflow engine. Keep this issue open/In Progress until review and delivery.

  5. bbottema commented on Oct 18, 2026

    @bbottema
    OwnerAuthor

    Implemented and accepted for 10.0.0. Convert a received notification as usual, then inspect its typed delivery report:

    Email notification = SimpleJavaMail.fromDefaults()
            .converter()
            .mimeMessageToEmailBuilder(incomingMessage)
            .buildEmail();
    
    DeliveryStatusReport report = notification.getDeliveryStatusReport();
    if (report != null) {
        System.out.println("Envelope ID: " + report.getEnvelopeId());
        for (RecipientDeliveryReport recipient : report.getRecipients()) {
            System.out.println(recipient.getAction() + " " + recipient.getStatusCode());
            ReportedRecipient target = recipient.getFinalRecipient();
            if (target != null && target.getMailbox() != null) {
                System.out.println(target.getMailbox().getAddress());
            }
        }
        report.getWarnings().forEach(System.out::println);
    }

    incomingMessage is the application's received MimeMessage. An ordinary email has no report. Optional fields can be absent; unfamiliar address/diagnostic formats retain their original values rather than being forced into a mailbox or SMTP reply.

    Malformed notifications keep whatever can be interpreted safely, with warnings. Ambiguous facts remain unavailable, and exact/protected source bytes stay authoritative. The application still decides whether to trust the notification, which submission it belongs to, and what action to take; a report is not an automatic retry instruction.

    Pushed as implementation, architecture, guidance and comparison progress, and the website walkthrough.

    The integration/Strategic Patterns work remains untouched under #764. This completes #763, not a published 10.0.0 release.

  6. moved this from In Progress to Done in Simple Java Mail 10.0.0on Oct 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions