generated from coulomb/repo-seed
1788 lines
60 KiB
Markdown
1788 lines
60 KiB
Markdown
# HybridmailAdapterSpecification.md
|
||
|
||
## 1. Document Status
|
||
|
||
**Document:** HybridmailAdapterSpecification.md
|
||
**Project:** hybridmail-connect
|
||
**Target Integration:** coordination-engine
|
||
**Adapter Contract:** AdapterInterfaceSpecification.md v1.0
|
||
**Status:** Draft v1.0
|
||
**Primary Scope:** Hybrid mail submission, production, postal handover, return-mail evidence, registered/delivery-confirmation variants, and vendor-specific hybrid-mail provider integration.
|
||
|
||
## 2. Purpose
|
||
|
||
This document specifies how `hybridmail-connect` models hybrid mail as a communication, delivery, and evidence channel and how it integrates with `coordination-engine`.
|
||
|
||
Hybrid mail means that a digital payload, usually a PDF document, is submitted to a provider that performs physical production and postal dispatch. The provider may validate the document, print it, fold it, insert it into an envelope, frank it, hand it over to a postal carrier, and optionally provide tracking, return-mail information, registered-mail evidence, or delivery-confirmation evidence.
|
||
|
||
Unlike email, SMS, RSS, or XMPP, hybrid mail has a physical production and delivery chain. The adapter therefore needs to model both digital submission and physical fulfillment.
|
||
|
||
The goal of this specification is to define a provider-neutral hybrid-mail baseline that can be implemented in vendor-specific flavors for providers such as:
|
||
|
||
* Deutsche Post / E-POSTBUSINESS API
|
||
* Pingen
|
||
* Binect
|
||
* future hybrid-mail providers
|
||
|
||
The adapter MUST support a superset model with capability flags, because providers differ in document validation, upload flow, print options, postal products, return-mail processing, preview handling, status granularity, webhooks, registered-letter support, and international delivery.
|
||
|
||
## 3. Core Principle
|
||
|
||
Hybrid mail is a controlled physical-delivery channel initiated through digital submission.
|
||
|
||
The adapter MUST distinguish:
|
||
|
||
```text
|
||
digital submission
|
||
provider acceptance
|
||
document validation
|
||
production readiness
|
||
print production
|
||
enveloping
|
||
franking
|
||
handover to postal carrier
|
||
postal delivery evidence
|
||
registered or tracked delivery evidence
|
||
undeliverable / return-mail evidence
|
||
physical delivery uncertainty
|
||
coordination result evidence
|
||
```
|
||
|
||
Normal physical letter dispatch usually cannot prove that the intended recipient personally received, opened, read, understood, or acted on the payload.
|
||
|
||
The adapter reports hybrid-mail evidence. `coordination-engine` decides whether that evidence satisfies the coordination case.
|
||
|
||
## 4. Architectural Role
|
||
|
||
### 4.1 Standalone Role
|
||
|
||
As a standalone component, `hybridmail-connect` provides:
|
||
|
||
* provider-neutral hybrid-mail submission
|
||
* PDF upload and document registration
|
||
* single-letter and bulk/serial-letter handling
|
||
* document validation
|
||
* address validation result normalization
|
||
* print and shipping option abstraction
|
||
* attachment handling
|
||
* preview retrieval where supported
|
||
* production status tracking
|
||
* postal handover status tracking
|
||
* return-mail/undeliverable processing
|
||
* registered-mail or delivery-confirmation tracking where supported
|
||
* vendor-specific provider abstraction
|
||
* hybrid-mail timeline and evidence assessment
|
||
* provider health and cutoff-time diagnostics
|
||
* normalized hybrid-mail evidence events
|
||
|
||
### 4.2 coordination-engine Adapter Role
|
||
|
||
As a `coordination-engine` adapter, `hybridmail-connect` provides:
|
||
|
||
#### Actions
|
||
|
||
* `delivery.submit_payload`
|
||
* `delivery.submit_letter`
|
||
* `delivery.submit_bulk`
|
||
* `delivery.validate_payload`
|
||
* `delivery.add_attachment`
|
||
* `delivery.set_options`
|
||
* `delivery.request_preview`
|
||
* `delivery.approve_for_sending`
|
||
* `delivery.cancel`
|
||
* `delivery.request_status`
|
||
* `delivery.request_return_info`
|
||
* `delivery.request_registered_tracking`
|
||
* `notification.register_tracking_context`
|
||
|
||
#### Signals
|
||
|
||
* `payload.validation_failed`
|
||
* `payload.validation_passed`
|
||
* `delivery.payload.submitted`
|
||
* `delivery.payload.accepted`
|
||
* `delivery.payload.rejected`
|
||
* `delivery.payload.available`
|
||
* `delivery.production.pending`
|
||
* `delivery.production.started`
|
||
* `delivery.production.completed`
|
||
* `delivery.postal.handed_over`
|
||
* `delivery.postal.in_transit`
|
||
* `delivery.postal.delivered`
|
||
* `delivery.postal.delivery_confirmed`
|
||
* `delivery.postal.undeliverable`
|
||
* `delivery.postal.return_received`
|
||
* `delivery.postal.forwarded`
|
||
* `delivery.postal.address_corrected`
|
||
* `delivery.postal.status_unknown`
|
||
* `delivery.postal.expired_without_final_status`
|
||
* `system.provider.degraded`
|
||
* `system.provider.unavailable`
|
||
|
||
Some of these normalized events will not be available for all vendors. Provider flavors MUST declare which ones they support.
|
||
|
||
## 5. Relationship to coordination-engine
|
||
|
||
`hybridmail-connect` does not own:
|
||
|
||
* `CoordinationCase`
|
||
* intended result evaluation
|
||
* participant-level success
|
||
* case-level success
|
||
* legal notice interpretation
|
||
* proof that the recipient opened or read the letter
|
||
* contract acceptance
|
||
* payment settlement
|
||
* signature completion
|
||
* follow-up and escalation policy
|
||
|
||
`hybridmail-connect` owns:
|
||
|
||
* hybrid-mail provider abstraction
|
||
* document submission
|
||
* provider identifiers
|
||
* document validation result mapping
|
||
* print/shipping option mapping
|
||
* status polling and webhook ingestion
|
||
* physical-production status normalization
|
||
* postal-handover status normalization
|
||
* return-mail / undeliverable status normalization
|
||
* registered-letter or delivery-confirmation evidence normalization
|
||
* hybrid-mail-native message timeline
|
||
* hybrid-mail evidence assessment
|
||
|
||
The boundary rule is:
|
||
|
||
> hybridmail-connect reports what happened in the hybrid-mail channel and what that may indicate. coordination-engine decides what that means for the coordination case.
|
||
|
||
## 6. Hybrid Mail as Delivery Channel
|
||
|
||
Within `coordination-engine`, hybrid mail is primarily a **delivery channel**, not just a notification channel.
|
||
|
||
It is used when the communication payload itself is physically delivered as a paper letter.
|
||
|
||
Examples:
|
||
|
||
```text
|
||
PDF letter submitted for physical mailing
|
||
invoice printed and posted
|
||
contract notice sent by post
|
||
dunning letter sent as registered mail
|
||
mass mailing sent as bulk/serial letters
|
||
confidential employee payroll letter mailed physically
|
||
```
|
||
|
||
Hybrid mail may also produce notification-like evidence, because physical payload delivery is often treated as a strong delivery attempt. However, even physical delivery normally does not prove that the intended human personally read the letter.
|
||
|
||
For high-assurance scenarios, hybrid-mail evidence may be combined with:
|
||
|
||
* registered-mail evidence
|
||
* delivery confirmation
|
||
* return-mail processing
|
||
* manual evidence
|
||
* recipient response
|
||
* payment event
|
||
* signature event
|
||
* portal access
|
||
* acknowledgement
|
||
|
||
## 7. Provider Landscape and Superset Baseline
|
||
|
||
The public provider material suggests the following baseline capabilities.
|
||
|
||
### 7.1 Deutsche Post / E-POSTBUSINESS API Baseline
|
||
|
||
The Deutsche Post E-POSTBUSINESS API supports automated digital submission of PDF documents for physical mail shipment. It includes PDF upload, single and bulk processing, status requests, registered-letter use cases, German and international receivers, and requires attention to PDF/A-1b, address and layout requirements, metadata, and size constraints. It uses authenticated API access and rate limits. It provides process state and delivery/error information where available.
|
||
|
||
### 7.2 Pingen Baseline
|
||
|
||
Pingen supports a letter API with SDKs, OAuth-style client credential examples, file upload, letter creation, configurable address position, auto-send control, idempotency-key headers, rate limiting, configurable send limits, staging/sandbox, Track & Trace, webhooks, document validation, print and delivery options, return-mail processing, and delivery-confirmation-related webhook categories.
|
||
|
||
Pingen explicitly distinguishes status tracking through handover and return-mail processing from ordinary post-office delivery confirmation. This is central for evidence grading.
|
||
|
||
### 7.3 Binect Baseline
|
||
|
||
Binect exposes a REST/Swagger API for digital letter dispatch with workflows such as document upload, attachment upload, shipping option configuration, preview retrieval, sending, and status queries. It validates uploaded documents for postal suitability, including address position, address format, and restricted areas. It supports single and serial/bulk letter concepts and provides shipping/production status information.
|
||
|
||
### 7.4 Superset Design Implication
|
||
|
||
The adapter MUST define a provider-neutral superset and require each provider flavor to expose a capability descriptor.
|
||
|
||
Capabilities should be feature-gated rather than assumed.
|
||
|
||
Examples:
|
||
|
||
```text
|
||
supports_preview
|
||
supports_webhooks
|
||
supports_polling
|
||
supports_bulk_upload
|
||
supports_serial_letters
|
||
supports_attachments
|
||
supports_registered_mail
|
||
supports_delivery_confirmation
|
||
supports_return_mail
|
||
supports_address_correction
|
||
supports_international_mail
|
||
supports_pdfa_validation
|
||
supports_color_option
|
||
supports_duplex_option
|
||
supports_envelope_selection
|
||
supports_cancel_before_production
|
||
supports_staging_environment
|
||
```
|
||
|
||
## 8. Hybrid Mail Lifecycle Model
|
||
|
||
`hybridmail-connect` models a hybrid-mail delivery as a lifecycle with observable phases.
|
||
|
||
```text
|
||
letter.created
|
||
letter.payload_received
|
||
letter.rendered
|
||
letter.render_failed
|
||
letter.upload_requested
|
||
letter.accepted_by_adapter
|
||
letter.rejected_by_adapter
|
||
letter.uploaded_to_provider
|
||
letter.accepted_by_provider
|
||
letter.rejected_by_provider
|
||
letter.validation_started
|
||
letter.validation_passed
|
||
letter.validation_failed
|
||
letter.action_required
|
||
letter.preview_available
|
||
letter.options_set
|
||
letter.ready_for_sending
|
||
letter.submitted_for_sending
|
||
letter.cancelled_before_production
|
||
letter.processing_started
|
||
letter.transferred_for_printing
|
||
letter.printed
|
||
letter.enveloped
|
||
letter.franked
|
||
letter.handed_to_postal_service
|
||
letter.in_postal_delivery
|
||
letter.delivered_confirmed
|
||
letter.registered_delivery_event
|
||
letter.undeliverable_reported
|
||
letter.return_mail_received
|
||
letter.address_corrected
|
||
letter.forwarded
|
||
letter.finalized
|
||
letter.status_unknown
|
||
letter.expired_without_final_status
|
||
```
|
||
|
||
The lifecycle is provider-dependent. Not every provider exposes every state.
|
||
|
||
The lifecycle is also not strictly linear. Late return-mail events may arrive after a letter was previously considered handed over or even after a case moved to another state.
|
||
|
||
## 9. Letter, Document, Attempt, Batch, and Recipient Model
|
||
|
||
The adapter MUST distinguish at least six layers.
|
||
|
||
### 9.1 HybridmailLetter
|
||
|
||
The logical letter delivery created by a client or coordination case.
|
||
|
||
```yaml
|
||
HybridmailLetter:
|
||
hybridmail_letter_id: string
|
||
coordination_case_id: string?
|
||
participant_id: string?
|
||
purpose: string?
|
||
payload_ref: ResourceRef
|
||
document_ref: HybridmailDocumentRef?
|
||
recipient: PostalRecipient
|
||
sender: PostalSender?
|
||
options: HybridmailOptions?
|
||
tracking_context: TrackingContext
|
||
created_at: timestamp
|
||
```
|
||
|
||
### 9.2 HybridmailDocumentRef
|
||
|
||
The submitted document or generated print artifact.
|
||
|
||
```yaml
|
||
HybridmailDocumentRef:
|
||
document_id: string
|
||
provider_document_id: string?
|
||
document_type: pdf | pdfa | postscript | other
|
||
version: string?
|
||
page_count: integer?
|
||
sheet_count: integer?
|
||
color_pages: integer?
|
||
grayscale_pages: integer?
|
||
simplex_pages: integer?
|
||
duplex_pages: integer?
|
||
integrity_hash: string?
|
||
validation_state: unknown | pending | passed | action_required | failed
|
||
metadata: object?
|
||
```
|
||
|
||
### 9.3 HybridmailAttempt
|
||
|
||
One submission attempt through one provider/configuration.
|
||
|
||
```yaml
|
||
HybridmailAttempt:
|
||
hybridmail_attempt_id: string
|
||
hybridmail_letter_id: string
|
||
provider_name: string
|
||
provider_account_ref: string?
|
||
provider_document_id: string?
|
||
provider_letter_id: string?
|
||
provider_sending_id: string?
|
||
provider_tracking_id: string?
|
||
state: HybridmailAttemptState
|
||
created_at: timestamp
|
||
updated_at: timestamp
|
||
```
|
||
|
||
### 9.4 HybridmailBatch
|
||
|
||
A batch or serial-letter group.
|
||
|
||
```yaml
|
||
HybridmailBatch:
|
||
batch_id: string
|
||
provider_batch_id: string?
|
||
coordination_case_id: string?
|
||
batch_type: bulk | serial | campaign | mixed | unknown
|
||
letters:
|
||
- hybridmail_letter_id
|
||
state: HybridmailBatchState
|
||
created_at: timestamp
|
||
updated_at: timestamp
|
||
```
|
||
|
||
A batch can have partial success. Each child letter must retain its own evidence state.
|
||
|
||
### 9.5 PostalRecipient
|
||
|
||
The postal recipient extracted, provided, or inferred.
|
||
|
||
```yaml
|
||
PostalRecipient:
|
||
recipient_id: string?
|
||
name_lines:
|
||
- string
|
||
organization: string?
|
||
street: string?
|
||
house_number: string?
|
||
address_addition: string?
|
||
postal_code: string?
|
||
city: string?
|
||
region: string?
|
||
country_code: string?
|
||
country_name: string?
|
||
address_source: extracted_from_document | provided_metadata | provider_detected | manual | unknown
|
||
address_quality: PostalAddressQuality?
|
||
```
|
||
|
||
### 9.6 PostalSender
|
||
|
||
```yaml
|
||
PostalSender:
|
||
sender_id: string?
|
||
name_lines:
|
||
- string
|
||
organization: string?
|
||
return_address: PostalRecipient?
|
||
billing_account_ref: string?
|
||
sender_identity_ref: string?
|
||
```
|
||
|
||
## 10. Hybrid Mail Options Model
|
||
|
||
The adapter MUST support a provider-neutral print and postal option model.
|
||
|
||
```yaml
|
||
HybridmailOptions:
|
||
color_mode: color | grayscale | provider_default | unknown
|
||
print_sides: simplex | duplex | provider_default | unknown
|
||
envelope_type: c5 | c4 | window_left | window_right | no_window | provider_default | unknown
|
||
address_position: left | right | metadata | extracted | provider_default | unknown
|
||
postage_product: standard | priority | economy | registered | registered_return_receipt | delivery_confirmation | international | dialogpost | provider_specific
|
||
country_scope: domestic | international | mixed | unknown
|
||
dispatch_mode: manual_review | auto_send | submit_later | scheduled
|
||
desired_dispatch_date: date?
|
||
cutoff_policy_ref: string?
|
||
return_mail_handling: none | provider_processed | scan_return | digital_return_info | physical_return | unknown
|
||
address_correction_requested: boolean?
|
||
sustainability_option: none | carbon_reduced | provider_default | provider_specific
|
||
metadata: object?
|
||
```
|
||
|
||
Provider flavors MUST map their native options into this model and declare unsupported fields.
|
||
|
||
## 11. Document Validation Model
|
||
|
||
Document validation is central to hybrid mail.
|
||
|
||
```yaml
|
||
HybridmailValidationResult:
|
||
document_id: string
|
||
validation_state: pending | passed | action_required | failed | unknown
|
||
issues:
|
||
- HybridmailValidationIssue
|
||
validated_at: timestamp?
|
||
provider_validation_ref: string?
|
||
```
|
||
|
||
```yaml
|
||
HybridmailValidationIssue:
|
||
issue_code: string
|
||
severity: info | warning | action_required | fatal
|
||
category: format | page_size | pdfa | address | restricted_area | margins | file_size | page_count | metadata | attachment | postage | country | provider_policy | unknown
|
||
message: string
|
||
page_number: integer?
|
||
bounding_box: object?
|
||
fixable: boolean?
|
||
```
|
||
|
||
Common validation categories:
|
||
|
||
```text
|
||
invalid_pdf
|
||
invalid_pdfa
|
||
unsupported_file_type
|
||
not_a4_portrait
|
||
invalid_page_size
|
||
file_too_large
|
||
too_many_pages
|
||
address_not_detected
|
||
address_invalid
|
||
address_position_invalid
|
||
restricted_area_violation
|
||
barcode_area_violation
|
||
margin_violation
|
||
unsupported_country
|
||
unsupported_product
|
||
attachment_invalid
|
||
insufficient_credit
|
||
```
|
||
|
||
Validation failure usually maps to strong failure of the hybrid-mail attempt, but not necessarily failure of the coordination case if another channel or corrected document can be used.
|
||
|
||
## 12. Preview Model
|
||
|
||
Some providers support preview retrieval before dispatch.
|
||
|
||
```yaml
|
||
HybridmailPreview:
|
||
preview_id: string
|
||
document_id: string
|
||
provider_preview_id: string?
|
||
preview_type: pdf | png | image | metadata | unknown
|
||
preview_uri: string?
|
||
generated_at: timestamp
|
||
expires_at: timestamp?
|
||
metadata: object?
|
||
```
|
||
|
||
Preview evidence maps to operational readiness, not physical delivery.
|
||
|
||
## 13. Hybrid Mail Evidence Assessment
|
||
|
||
`hybridmail-connect` should provide a hybrid-mail-native assessment separate from coordination-engine state.
|
||
|
||
```yaml
|
||
HybridmailEvidenceAssessment:
|
||
hybridmail_letter_id: string
|
||
participant_id: string?
|
||
category: success | fail | undef
|
||
subclass: string
|
||
confidence: low | medium | high
|
||
strongest_signal: string?
|
||
evidence_summary:
|
||
- string
|
||
recommended_coordination_interpretation: string?
|
||
```
|
||
|
||
The assessment categories are adapter-level hints.
|
||
|
||
### 13.1 Hybrid-Mail Adapter Success
|
||
|
||
Hybrid-mail-level `success` means the channel produced strong hybrid-mail evidence.
|
||
|
||
Possible subclasses:
|
||
|
||
```text
|
||
success.provider_accepted
|
||
success.validation_passed
|
||
success.submitted_for_sending
|
||
success.production_started
|
||
success.transferred_for_printing
|
||
success.handed_to_postal_service
|
||
success.registered_delivery_event
|
||
success.delivery_confirmed
|
||
success.return_info_processed
|
||
```
|
||
|
||
Important: These are not automatically coordination success.
|
||
|
||
For ordinary letters, `success.handed_to_postal_service` is strong dispatch evidence but not proof of physical delivery or human awareness.
|
||
|
||
### 13.2 Hybrid-Mail Adapter Fail
|
||
|
||
Hybrid-mail-level `fail` indicates strong evidence that the hybrid-mail attempt failed.
|
||
|
||
Subclasses:
|
||
|
||
```text
|
||
fail.missing_payload
|
||
fail.invalid_document
|
||
fail.validation_failed
|
||
fail.action_required_unresolved
|
||
fail.invalid_address
|
||
fail.unsupported_country
|
||
fail.unsupported_product
|
||
fail.insufficient_credit
|
||
fail.provider_rejected
|
||
fail.upload_failed
|
||
fail.production_failed
|
||
fail.cancelled
|
||
fail.postal_undeliverable
|
||
fail.return_mail_received
|
||
fail.expired_before_handover
|
||
```
|
||
|
||
### 13.3 Hybrid-Mail Adapter Undef
|
||
|
||
Hybrid-mail-level `undef` is used when the adapter cannot determine physical delivery, recipient awareness, or final postal outcome.
|
||
|
||
Subclasses:
|
||
|
||
```text
|
||
undef.pending
|
||
undef.uploaded_only
|
||
undef.provider_accepted_only
|
||
undef.validation_pending
|
||
undef.ready_but_not_sent
|
||
undef.submitted_for_sending
|
||
undef.processing
|
||
undef.transferred_for_printing
|
||
undef.handed_to_postal_service_but_delivery_unproven
|
||
undef.postal_delivery_unknown
|
||
undef.registered_tracking_pending
|
||
undef.return_mail_pending
|
||
undef.no_final_status_expected
|
||
undef.conflicting_evidence
|
||
undef.channel_degraded
|
||
```
|
||
|
||
For ordinary physical letters, the adapter should expect `undef.handed_to_postal_service_but_delivery_unproven` to be common.
|
||
|
||
## 14. Detailed Scenario Classification
|
||
|
||
### 14.1 Pre-Submission Scenarios
|
||
|
||
| Scenario | Hybridmail assessment | Normalized event | Notes |
|
||
| -------------------------------------- | --------------------------------------------- | --------------------------- | ----------------------------- |
|
||
| Missing PDF/payload | `fail.missing_payload` | `delivery.payload.failed` | No delivery possible |
|
||
| Unsupported document format | `fail.invalid_document` | `payload.validation_failed` | Provider may reject |
|
||
| Invalid PDF/PDF-A | `fail.validation_failed` | `payload.validation_failed` | Provider-specific |
|
||
| Non-A4 or unsupported page size | `fail.validation_failed` | `payload.validation_failed` | Common hybrid-mail constraint |
|
||
| Address not detected | `fail.invalid_address` or `action_required` | `payload.validation_failed` | May be fixable |
|
||
| Address in wrong window position | `fail.validation_failed` or `action_required` | `payload.validation_failed` | Provider-specific |
|
||
| Restricted area violation | `fail.validation_failed` or `action_required` | `payload.validation_failed` | Print/postal layout issue |
|
||
| Unsupported destination country | `fail.unsupported_country` | `delivery.payload.rejected` | Route unavailable |
|
||
| Unsupported postal product | `fail.unsupported_product` | `delivery.payload.rejected` | Option mismatch |
|
||
| Insufficient credit/account problem | `fail.insufficient_credit` | `delivery.payload.rejected` | Operational/account failure |
|
||
| Provider unavailable before acceptance | `undef.pending` or provider fail | action error | Retry-dependent |
|
||
|
||
### 14.2 Upload and Validation Scenarios
|
||
|
||
| Scenario | Hybridmail assessment | Normalized event | Notes |
|
||
| ------------------------ | ------------------------------------------ | ---------------------------------------------------- | --------------------------- |
|
||
| Adapter accepted request | `undef.pending` | `delivery.payload.submitted` | Adapter accepted work |
|
||
| Provider accepted upload | `undef.provider_accepted_only` | `delivery.payload.accepted` | Digital submission accepted |
|
||
| Provider rejected upload | `fail.provider_rejected` | `delivery.payload.rejected` | Strong attempt failure |
|
||
| Validation started | `undef.validation_pending` | `payload.validation_started` | Operational status |
|
||
| Validation passed | `success.validation_passed` | `payload.validation_passed` | Ready for options/send |
|
||
| Action required | `fail.action_required_unresolved` or undef | `payload.validation_failed` with severity | May be fixable |
|
||
| Validation failed fatal | `fail.validation_failed` | `payload.validation_failed` | Cannot send |
|
||
| Preview available | operational success | `delivery.payload.available` | Review evidence only |
|
||
| Attachment accepted | operational success | `delivery.payload.accepted` with attachment metadata | Not final delivery |
|
||
| Attachment failed | `fail.validation_failed` | `payload.validation_failed` | Must be corrected |
|
||
|
||
### 14.3 Sending and Production Scenarios
|
||
|
||
| Scenario | Hybridmail assessment | Normalized event | Notes |
|
||
| --------------------------- | ---------------------------------- | ------------------------------------------------ | --------------------------- |
|
||
| Options set | operational success | metadata event | Not delivery |
|
||
| Ready for sending | `undef.ready_but_not_sent` | `delivery.payload.available` | Awaiting dispatch approval |
|
||
| Submitted for sending | `success.submitted_for_sending` | `delivery.payload.submitted` | Provider instructed to send |
|
||
| Cancelled before production | `fail.cancelled` or cancelled | `delivery.payload.failed` or manual cancellation | Depends on policy |
|
||
| Processing started | `undef.processing` | `delivery.production.started` | Production chain began |
|
||
| Transferred for printing | `success.transferred_for_printing` | `delivery.production.started` | Strong production evidence |
|
||
| Printed | production success | `delivery.production.completed` | Not postal handover |
|
||
| Enveloped/franked | production success | `delivery.production.completed` | Not postal delivery |
|
||
| Production failed | `fail.production_failed` | `delivery.payload.failed` | Strong channel failure |
|
||
| Handover to postal service | `success.handed_to_postal_service` | `delivery.postal.handed_over` | Strong dispatch evidence |
|
||
| Same-day cutoff missed | `undef.processing` or delayed | metadata/channel warning | Adjust expected timing |
|
||
|
||
### 14.4 Postal Delivery Scenarios
|
||
|
||
| Scenario | Hybridmail assessment | Normalized event | Notes |
|
||
| ------------------------------ | ------------------------------------------------------ | ----------------------------------------- | ---------------------------------- |
|
||
| Ordinary letter handed over | `undef.handed_to_postal_service_but_delivery_unproven` | `delivery.postal.handed_over` | Strong dispatch, delivery unproven |
|
||
| Postal tracking ID received | `undef.postal_delivery_unknown` | `delivery.postal.in_transit` | Stronger traceability |
|
||
| Registered tracking event | `success.registered_delivery_event` | `delivery.postal.in_transit` or confirmed | Depends event |
|
||
| Delivery confirmed | `success.delivery_confirmed` | `delivery.postal.delivery_confirmed` | Strong physical delivery evidence |
|
||
| Return receipt received | `success.delivery_confirmed` | `delivery.postal.delivery_confirmed` | Stronger evidence |
|
||
| Undeliverable reported | `fail.postal_undeliverable` | `delivery.postal.undeliverable` | Strong negative evidence |
|
||
| Return mail received | `fail.return_mail_received` | `delivery.postal.return_received` | Strong negative evidence |
|
||
| Address corrected | operational/address evidence | `delivery.postal.address_corrected` | May support future correction |
|
||
| Forwarded due to moving | `undef.forwarded` or success-ish | `delivery.postal.forwarded` | Delivery path changed |
|
||
| No final status expected | `undef.no_final_status_expected` | metadata | Common for ordinary letters |
|
||
| No return after waiting period | still `undef` unless policy accepts | timeout metadata | Absence of return is not proof |
|
||
|
||
### 14.5 Batch / Serial Letter Scenarios
|
||
|
||
| Scenario | Hybridmail assessment | Normalized event | Notes |
|
||
| ------------------------------- | --------------------- | -------------------------------------- | ------------------------------- |
|
||
| Batch accepted | batch-level pending | `delivery.payload.submitted` | Child states needed |
|
||
| Some children validation-failed | partial | per-letter `payload.validation_failed` | Batch partial state |
|
||
| Some children ready | partial success | per-letter validation passed | Each letter tracked |
|
||
| Batch submitted | batch-level submitted | `delivery.payload.submitted` | Not each delivery |
|
||
| Some children handed over | partial dispatch | per-letter handover | Case aggregation needed |
|
||
| Some children undeliverable | partial negative | per-letter return/undeliverable | Do not fail whole batch blindly |
|
||
|
||
## 15. Adapter-to-Coordination Mapping
|
||
|
||
### 15.1 Core Mapping Table
|
||
|
||
| Hybridmail-native event | Hybridmail assessment | coordination-engine event | Coordination interpretation |
|
||
| ------------------------ | ---------------------------------- | ------------------------------------------------ | ---------------------------- |
|
||
| Letter created | `undef.pending` | `delivery.payload.submitted` | Local delivery object exists |
|
||
| Provider upload accepted | `undef.provider_accepted_only` | `delivery.payload.accepted` | Digital submission accepted |
|
||
| Provider upload rejected | `fail.provider_rejected` | `delivery.payload.rejected` | Strong attempt failure |
|
||
| Validation passed | `success.validation_passed` | `payload.validation_passed` | Production-ready |
|
||
| Validation failed | `fail.validation_failed` | `payload.validation_failed` | Must correct or fallback |
|
||
| Preview available | operational success | `delivery.payload.available` | Review evidence |
|
||
| Ready for sending | `undef.ready_but_not_sent` | `delivery.payload.available` | Awaiting send |
|
||
| Submitted for sending | `success.submitted_for_sending` | `delivery.payload.submitted` | Provider instructed |
|
||
| Processing started | `undef.processing` | `delivery.production.started` | Production began |
|
||
| Transferred for printing | `success.transferred_for_printing` | `delivery.production.started` | Strong production evidence |
|
||
| Production completed | production success | `delivery.production.completed` | Printed/enveloped/franked |
|
||
| Handed to post | `success.handed_to_postal_service` | `delivery.postal.handed_over` | Strong dispatch evidence |
|
||
| Tracking ID received | stronger tracking evidence | `delivery.postal.in_transit` | Physical route traceability |
|
||
| Delivery confirmed | `success.delivery_confirmed` | `delivery.postal.delivery_confirmed` | Strong delivery evidence |
|
||
| Undeliverable | `fail.postal_undeliverable` | `delivery.postal.undeliverable` | Strong negative evidence |
|
||
| Return mail received | `fail.return_mail_received` | `delivery.postal.return_received` | Strong negative evidence |
|
||
| Address corrected | address signal | `delivery.postal.address_corrected` | Useful for contact registry |
|
||
| Cancelled | `fail.cancelled` | `delivery.payload.failed` or manual cancellation | Attempt stopped |
|
||
|
||
### 15.2 Coordination Undef Subclasses
|
||
|
||
`coordination-engine` may derive these uncertainty classes from hybrid-mail evidence:
|
||
|
||
```text
|
||
undef.pending
|
||
undef.provider_accepted_only
|
||
undef.validation_pending
|
||
undef.ready_but_not_sent
|
||
undef.production_pending
|
||
undef.handed_to_postal_service_but_delivery_unproven
|
||
undef.postal_delivery_unknown
|
||
undef.no_final_status_expected
|
||
undef.return_mail_pending
|
||
undef.conflicting_evidence
|
||
undef.channel_degraded
|
||
undef.escalation_required
|
||
```
|
||
|
||
Hybrid mail commonly produces:
|
||
|
||
```text
|
||
undef.handed_to_postal_service_but_delivery_unproven
|
||
undef.no_final_status_expected
|
||
undef.return_mail_pending
|
||
```
|
||
|
||
for ordinary letters.
|
||
|
||
## 16. Evidence Grading Rules
|
||
|
||
### 16.1 Provider Upload Accepted
|
||
|
||
```yaml
|
||
event_type: delivery.payload.accepted
|
||
evidence_grade:
|
||
strength: weak
|
||
actor_certainty: none
|
||
authority_certainty: none
|
||
payload_certainty: medium
|
||
interaction_certainty: none
|
||
timing_certainty: medium
|
||
channel_certainty: medium
|
||
non_repudiation_strength: low
|
||
notes:
|
||
- Provider accepted the digital submission.
|
||
- Does not prove validation, production, postal handover, or delivery.
|
||
```
|
||
|
||
### 16.2 Validation Passed
|
||
|
||
```yaml
|
||
event_type: payload.validation_passed
|
||
evidence_grade:
|
||
strength: medium
|
||
actor_certainty: none
|
||
authority_certainty: none
|
||
payload_certainty: high
|
||
interaction_certainty: none
|
||
timing_certainty: high
|
||
channel_certainty: high
|
||
non_repudiation_strength: low
|
||
notes:
|
||
- Document passed provider validation for print/postal processing.
|
||
- Does not prove dispatch or delivery.
|
||
```
|
||
|
||
### 16.3 Validation Failed
|
||
|
||
```yaml
|
||
event_type: payload.validation_failed
|
||
evidence_grade:
|
||
strength: negative
|
||
actor_certainty: none
|
||
authority_certainty: none
|
||
payload_certainty: high
|
||
interaction_certainty: none
|
||
timing_certainty: high
|
||
channel_certainty: high
|
||
non_repudiation_strength: low
|
||
notes:
|
||
- Document cannot be processed until corrected or replaced.
|
||
```
|
||
|
||
### 16.4 Submitted for Sending
|
||
|
||
```yaml
|
||
event_type: delivery.payload.submitted
|
||
evidence_grade:
|
||
strength: medium
|
||
actor_certainty: none
|
||
authority_certainty: none
|
||
payload_certainty: high
|
||
interaction_certainty: none
|
||
timing_certainty: high
|
||
channel_certainty: high
|
||
non_repudiation_strength: low
|
||
notes:
|
||
- Letter was submitted into the provider sending process.
|
||
- Does not prove print production or postal handover.
|
||
```
|
||
|
||
### 16.5 Transferred for Printing
|
||
|
||
```yaml
|
||
event_type: delivery.production.started
|
||
evidence_grade:
|
||
strength: medium
|
||
actor_certainty: none
|
||
authority_certainty: none
|
||
payload_certainty: high
|
||
interaction_certainty: none
|
||
timing_certainty: high
|
||
channel_certainty: high
|
||
non_repudiation_strength: low
|
||
notes:
|
||
- Letter was transferred to or started in print production.
|
||
- Does not prove postal handover.
|
||
```
|
||
|
||
### 16.6 Handed to Postal Service
|
||
|
||
```yaml
|
||
event_type: delivery.postal.handed_over
|
||
evidence_grade:
|
||
strength: strong
|
||
actor_certainty: none
|
||
authority_certainty: none
|
||
payload_certainty: high
|
||
interaction_certainty: none
|
||
timing_certainty: high
|
||
channel_certainty: high
|
||
non_repudiation_strength: medium
|
||
notes:
|
||
- Letter was handed over to the postal delivery chain.
|
||
- Strong dispatch evidence.
|
||
- Does not prove recipient receipt or reading.
|
||
```
|
||
|
||
### 16.7 Delivery Confirmed / Registered Event
|
||
|
||
```yaml
|
||
event_type: delivery.postal.delivery_confirmed
|
||
evidence_grade:
|
||
strength: strong
|
||
actor_certainty: low
|
||
authority_certainty: none
|
||
payload_certainty: high
|
||
interaction_certainty: low
|
||
timing_certainty: high
|
||
channel_certainty: high
|
||
non_repudiation_strength: medium
|
||
notes:
|
||
- Postal delivery confirmation or registered-mail event was received.
|
||
- This is strong physical-delivery evidence.
|
||
- It may still not prove that the intended human personally read the payload.
|
||
```
|
||
|
||
### 16.8 Return Mail / Undeliverable
|
||
|
||
```yaml
|
||
event_type: delivery.postal.return_received
|
||
evidence_grade:
|
||
strength: negative
|
||
actor_certainty: none
|
||
authority_certainty: none
|
||
payload_certainty: high
|
||
interaction_certainty: none
|
||
timing_certainty: high
|
||
channel_certainty: high
|
||
non_repudiation_strength: medium
|
||
notes:
|
||
- Letter was returned or reported undeliverable.
|
||
- Strong evidence that physical delivery failed for this attempt.
|
||
```
|
||
|
||
### 16.9 Address Correction
|
||
|
||
```yaml
|
||
event_type: delivery.postal.address_corrected
|
||
evidence_grade:
|
||
strength: medium
|
||
actor_certainty: none
|
||
authority_certainty: none
|
||
payload_certainty: medium
|
||
interaction_certainty: none
|
||
timing_certainty: high
|
||
channel_certainty: high
|
||
non_repudiation_strength: low
|
||
notes:
|
||
- Postal process or provider supplied address correction information.
|
||
- Useful for future delivery attempts and contact registry updates.
|
||
```
|
||
|
||
## 17. Status Timeline API
|
||
|
||
`hybridmail-connect` SHOULD expose a delivery timeline suitable for standalone diagnostics and coordination audit.
|
||
|
||
```yaml
|
||
HybridmailTimeline:
|
||
hybridmail_letter_id: string
|
||
provider_name: string
|
||
provider_document_id: string?
|
||
provider_letter_id: string?
|
||
provider_sending_id: string?
|
||
provider_tracking_id: string?
|
||
events:
|
||
- HybridmailTimelineEvent
|
||
current_assessment: HybridmailEvidenceAssessment
|
||
```
|
||
|
||
```yaml
|
||
HybridmailTimelineEvent:
|
||
event_id: string
|
||
event_type: string
|
||
occurred_at: timestamp
|
||
source: adapter | provider | print_center | postal_carrier | return_mail | operator
|
||
native_event_type: string?
|
||
normalized_event_type: string?
|
||
summary: string
|
||
evidence_grade: EvidenceGrade
|
||
raw_event_ref: string?
|
||
```
|
||
|
||
## 18. Adapter Descriptor
|
||
|
||
`hybridmail-connect` MUST expose an `AdapterDescriptor` compatible with AdapterInterfaceSpecification.md v1.0.
|
||
|
||
```yaml
|
||
adapter_id: hybridmail-connect.default
|
||
adapter_name: hybridmail-connect
|
||
adapter_version: 1.0.0
|
||
adapter_contract_version: 1.0
|
||
adapter_types:
|
||
- delivery
|
||
- communication
|
||
- document
|
||
- archive
|
||
provider_family: hybridmail
|
||
provider_name: configurable
|
||
deployment_mode: external
|
||
supported_channels:
|
||
- hybridmail
|
||
- postal_mail
|
||
supported_endpoint_types:
|
||
- postal_address
|
||
supported_actions:
|
||
- action_type: delivery.submit_letter
|
||
mode: async
|
||
idempotency_required: true
|
||
- action_type: delivery.submit_bulk
|
||
mode: async
|
||
idempotency_required: true
|
||
- action_type: delivery.validate_payload
|
||
mode: async
|
||
idempotency_required: true
|
||
- action_type: delivery.add_attachment
|
||
mode: async
|
||
idempotency_required: true
|
||
- action_type: delivery.set_options
|
||
mode: sync
|
||
idempotency_required: true
|
||
- action_type: delivery.request_preview
|
||
mode: async
|
||
idempotency_required: true
|
||
- action_type: delivery.approve_for_sending
|
||
mode: async
|
||
idempotency_required: true
|
||
- action_type: delivery.cancel
|
||
mode: async
|
||
idempotency_required: true
|
||
- action_type: delivery.request_status
|
||
mode: sync
|
||
idempotency_required: true
|
||
emitted_event_types:
|
||
- delivery.payload.submitted
|
||
- delivery.payload.accepted
|
||
- delivery.payload.rejected
|
||
- payload.validation_passed
|
||
- payload.validation_failed
|
||
- delivery.payload.available
|
||
- delivery.production.started
|
||
- delivery.production.completed
|
||
- delivery.postal.handed_over
|
||
- delivery.postal.in_transit
|
||
- delivery.postal.delivery_confirmed
|
||
- delivery.postal.undeliverable
|
||
- delivery.postal.return_received
|
||
- delivery.postal.forwarded
|
||
- delivery.postal.address_corrected
|
||
- delivery.postal.status_unknown
|
||
- system.provider.degraded
|
||
- system.provider.unavailable
|
||
evidence_profile:
|
||
strongest_evidence_level: strong
|
||
can_prove_human_awareness: false
|
||
can_prove_payload_delivery: partially
|
||
can_prove_identity: false
|
||
identity_profile:
|
||
identity_strength: none_to_low
|
||
authority_strength: none
|
||
limitations:
|
||
- Ordinary postal handover does not prove recipient receipt.
|
||
- Ordinary physical letters often do not provide final delivery confirmation.
|
||
- Delivery confirmation depends on postal product and provider support.
|
||
- Return-mail information may arrive late.
|
||
- Address extraction and validation differ by provider.
|
||
- Cancellation may only be possible before production starts.
|
||
- Batch-level status does not imply child-letter success.
|
||
```
|
||
|
||
## 19. Provider Flavor Descriptor
|
||
|
||
Each vendor-specific implementation MUST expose a `HybridmailProviderFlavorDescriptor`.
|
||
|
||
```yaml
|
||
HybridmailProviderFlavorDescriptor:
|
||
provider_name: dpag_epost | pingen | binect | other
|
||
provider_version: string?
|
||
supported_file_types:
|
||
- pdf
|
||
- pdfa
|
||
- postscript
|
||
supports_single_letter: boolean
|
||
supports_bulk: boolean
|
||
supports_serial_letters: boolean
|
||
supports_attachments: boolean
|
||
supports_preview: boolean
|
||
supports_webhooks: boolean
|
||
supports_polling: boolean
|
||
supports_registered_mail: boolean
|
||
supports_delivery_confirmation: boolean
|
||
supports_return_mail: boolean
|
||
supports_address_correction: boolean
|
||
supports_international_mail: boolean
|
||
supports_cancellation: boolean
|
||
supports_staging: boolean
|
||
supports_idempotency: boolean
|
||
supports_rate_limits: boolean
|
||
supported_print_options:
|
||
color_mode: boolean
|
||
simplex_duplex: boolean
|
||
envelope_selection: boolean
|
||
address_position: boolean
|
||
supported_postal_products:
|
||
- standard
|
||
- priority
|
||
- registered
|
||
- registered_return_receipt
|
||
- delivery_confirmation
|
||
- international
|
||
- dialogpost
|
||
- provider_specific
|
||
cutoff_times:
|
||
- country_scope: string
|
||
cutoff_local_time: string
|
||
notes: string?
|
||
limitations:
|
||
- string
|
||
```
|
||
|
||
## 20. Provider Flavor Baseline
|
||
|
||
### 20.1 DPAG / E-POSTBUSINESS Flavor
|
||
|
||
Likely capability baseline:
|
||
|
||
```yaml
|
||
provider_name: dpag_epost
|
||
supports_single_letter: true
|
||
supports_bulk: true
|
||
supports_serial_letters: true
|
||
supports_attachments: provider_specific
|
||
supports_preview: provider_specific
|
||
supports_webhooks: provider_specific
|
||
supports_polling: true
|
||
supports_registered_mail: true
|
||
supports_delivery_confirmation: registered_product_dependent
|
||
supports_return_mail: provider_specific
|
||
supports_address_correction: provider_specific
|
||
supports_international_mail: true
|
||
supports_pdfa_validation: true
|
||
supports_staging: true
|
||
supports_idempotency: provider_specific
|
||
supported_file_types:
|
||
- pdf
|
||
- pdfa
|
||
```
|
||
|
||
Key flavor notes:
|
||
|
||
```text
|
||
PDF/PDF-A handling is central.
|
||
PDF/A-1b knowledge is expected.
|
||
Address and layout requirements matter.
|
||
Status requests are core.
|
||
Registered-letter use cases are supported.
|
||
Bulk status information is relevant.
|
||
Activation, vendor/customer identifiers, and authenticated API access are central.
|
||
```
|
||
|
||
### 20.2 Pingen Flavor
|
||
|
||
Likely capability baseline:
|
||
|
||
```yaml
|
||
provider_name: pingen
|
||
supports_single_letter: true
|
||
supports_bulk: true
|
||
supports_serial_letters: true
|
||
supports_attachments: provider_specific
|
||
supports_preview: true
|
||
supports_webhooks: true
|
||
supports_polling: true
|
||
supports_registered_mail: true
|
||
supports_delivery_confirmation: product_dependent
|
||
supports_return_mail: true
|
||
supports_address_correction: provider_specific
|
||
supports_international_mail: true
|
||
supports_staging: true
|
||
supports_idempotency: true
|
||
supported_file_types:
|
||
- pdf
|
||
```
|
||
|
||
Key flavor notes:
|
||
|
||
```text
|
||
File upload and letter creation are distinct concepts.
|
||
Address position can be configured.
|
||
Auto-send can be controlled.
|
||
Track & Trace provides detailed processing events.
|
||
Webhooks cover document issues, sent documents, undeliverable documents, and delivered sent documents.
|
||
Return mail processing is a first-class feature.
|
||
Normal postal delivery confirmation is not generally available for ordinary letters.
|
||
```
|
||
|
||
### 20.3 Binect Flavor
|
||
|
||
Likely capability baseline:
|
||
|
||
```yaml
|
||
provider_name: binect
|
||
supports_single_letter: true
|
||
supports_bulk: true
|
||
supports_serial_letters: true
|
||
supports_attachments: true
|
||
supports_preview: true
|
||
supports_webhooks: provider_specific
|
||
supports_polling: true
|
||
supports_registered_mail: provider_specific
|
||
supports_delivery_confirmation: provider_specific
|
||
supports_return_mail: provider_specific
|
||
supports_address_correction: provider_specific
|
||
supports_international_mail: provider_specific
|
||
supports_staging: provider_specific
|
||
supports_idempotency: provider_specific
|
||
supported_file_types:
|
||
- pdf
|
||
- postscript
|
||
```
|
||
|
||
Key flavor notes:
|
||
|
||
```text
|
||
Document upload is a core workflow.
|
||
Attachments can be added.
|
||
Print and shipping options can be set.
|
||
PDF/PNG preview retrieval is supported.
|
||
Sending is performed separately after document preparation.
|
||
Status queries are supported.
|
||
Validation includes address position, address format, and restricted-area checks.
|
||
Default print/shipping options may be inherited and then overridden.
|
||
```
|
||
|
||
## 21. Action Request Handling
|
||
|
||
### 21.1 `delivery.submit_letter`
|
||
|
||
`delivery.submit_letter` submits a letter payload to a hybrid-mail provider.
|
||
|
||
Required fields:
|
||
|
||
```text
|
||
request_id
|
||
action_type
|
||
coordination_case_id
|
||
participant_id
|
||
payload_ref
|
||
target_endpoint
|
||
tracking_context
|
||
idempotency_key
|
||
requested_at
|
||
```
|
||
|
||
Example:
|
||
|
||
```yaml
|
||
request_id: req_001
|
||
action_type: delivery.submit_letter
|
||
coordination_case_id: case_123
|
||
participant_id: participant_456
|
||
channel: hybridmail
|
||
target_endpoint:
|
||
endpoint_type: postal_address
|
||
value: postal_recipient_ref_456
|
||
payload_ref:
|
||
ref_type: coordination_payload
|
||
ref_id: payload_777
|
||
uri: s3://bucket/document.pdf
|
||
integrity_hash: sha256:...
|
||
content:
|
||
payload_refs:
|
||
- ref_type: coordination_payload
|
||
ref_id: payload_777
|
||
tracking_context:
|
||
correlation_id: corr_789
|
||
coordination_case_id: case_123
|
||
participant_id: participant_456
|
||
delivery_id: delivery_001
|
||
payload_id: payload_777
|
||
idempotency_key: case_123:participant_456:hybridmail:delivery_001
|
||
requested_at: 2026-01-01T12:00:00Z
|
||
metadata:
|
||
hybridmail_options:
|
||
color_mode: grayscale
|
||
print_sides: duplex
|
||
envelope_type: window_left
|
||
postage_product: standard
|
||
```
|
||
|
||
### 21.2 Action Result
|
||
|
||
The adapter returns:
|
||
|
||
```yaml
|
||
request_id: req_001
|
||
adapter_id: hybridmail-connect.default
|
||
accepted: true
|
||
action_state: accepted
|
||
adapter_operation_id: hmop_001
|
||
provider_operation_id: providerop_001
|
||
initial_events:
|
||
- event_type: delivery.payload.submitted
|
||
received_at: 2026-01-01T12:00:01Z
|
||
```
|
||
|
||
This result does not prove validation, production, postal handover, or delivery.
|
||
|
||
## 22. Provider Abstraction
|
||
|
||
`hybridmail-connect` SHOULD support a provider abstraction layer.
|
||
|
||
Provider integration responsibilities:
|
||
|
||
* authenticate
|
||
* upload document
|
||
* create letter/document record
|
||
* add attachments
|
||
* configure options
|
||
* request preview
|
||
* submit for sending
|
||
* cancel where possible
|
||
* poll status
|
||
* ingest webhooks where supported
|
||
* normalize provider statuses
|
||
* parse validation issues
|
||
* parse return-mail information
|
||
* parse delivery-confirmation information
|
||
* expose provider health
|
||
|
||
Provider model:
|
||
|
||
```yaml
|
||
HybridmailProvider:
|
||
provider_name: string
|
||
provider_account_ref: string
|
||
supported_features:
|
||
- upload
|
||
- validation
|
||
- attachments
|
||
- options
|
||
- preview
|
||
- send
|
||
- cancel
|
||
- status_polling
|
||
- webhooks
|
||
- return_mail
|
||
- registered_mail
|
||
- delivery_confirmation
|
||
- bulk
|
||
- staging
|
||
event_mapping_ref: string
|
||
configuration_ref: string
|
||
```
|
||
|
||
Provider-specific modules should map to the hybrid-mail-native model first, then to normalized coordination events.
|
||
|
||
```text
|
||
Provider event
|
||
→ hybridmail-native event
|
||
→ HybridmailEvidenceAssessment
|
||
→ EvidenceEvent for coordination-engine
|
||
```
|
||
|
||
## 23. Native Provider Event Mapping
|
||
|
||
The adapter MUST support provider-specific mapping files or code modules.
|
||
|
||
Common provider-native event groups:
|
||
|
||
```text
|
||
uploaded
|
||
received
|
||
validated
|
||
validation_failed
|
||
ready
|
||
action_required
|
||
invalid
|
||
preview_available
|
||
submitted
|
||
processing
|
||
transferred_for_printing
|
||
printed
|
||
enveloped
|
||
franked
|
||
handed_to_post
|
||
sent
|
||
tracking_id_receivedered
|
||
delivery_confirmed
|
||
undeliverable
|
||
returned
|
||
address_corrected
|
||
forwarded
|
||
cancelled
|
||
failed
|
||
unknown
|
||
```
|
||
|
||
Important mapping rule:
|
||
|
||
Provider terms such as `sent`, `delivered`, or `posted` MUST be mapped according to the provider’s actual semantics.
|
||
|
||
For example:
|
||
|
||
```text
|
||
"handed to post" → delivery.postal.handed_over
|
||
"delivery confirmed" → delivery.postal.delivery_confirmed
|
||
"undeliverable" → delivery.postal.undeliverable
|
||
```
|
||
|
||
A provider status called `delivered` MUST NOT automatically mean `coordinatit success` unless its semantics are documented and the coordination policy accepts it.
|
||
|
||
## 24. Return Mail and Undeliverable Model
|
||
|
||
```yaml
|
||
HybridmailReturnEvent:
|
||
return_event_id: string
|
||
hybridmail_letter_id: string
|
||
provider_return_id: string?
|
||
postal_tracking_id: string?
|
||
return_type: undeliverable | address_unknown | recipient_moved | refused | deceased | insufficient_address | mailbox_inaccessible | other | unknown
|
||
address_correction: PostalRecipient?
|
||
return_document_ref: ResourceRef?
|
||
occurred_at: timestamp?
|
||
observed_at: timestamp
|
||
raw_event_ref: string?
|
||
```
|
||
|
||
Return events usually create strong negative delivery evidence but may also provide address-correction information useful for future attempts.
|
||
|
||
## 25. Registered / Delivery Confirmation Model
|
||
|
||
```yaml
|
||
HybridmailDeliveryConfirmation:
|
||
confirmation_id: string
|
||
hybridmail_letter_id: string
|
||
provider_tracking_id: string?
|
||
postal_tracking_id: string?
|
||
product_type: registered | registered_return_receipt | delivery_confirmation | provider_specific
|
||
status: in_transit | attempted | delivered | refused | undeliverable | returned | unknown
|
||
recipient_signature_ref: ResourceRef?
|
||
confirmation_document_ref: ResourceRef?
|
||
occurred_at: timestamp?
|
||
observed_at: timestamp
|
||
raw_event_ref: string?
|
||
```
|
||
|
||
Delivery confirmation is stronger than ordinary handover evidence, but the exact legal and business meaning remains scenario-specific.
|
||
|
||
## 26. Address Quality Model
|
||
|
||
```yaml
|
||
PostalAddressQuality:
|
||
validation_state: unknown | valid | action_required | invalid | corrected
|
||
country_supported: boolean?
|
||
address_position_valid: boolean?
|
||
address_format_valid: boolean?
|
||
postal_code_valid: boolean?
|
||
street_known: boolean?
|
||
recipient_known: boolean?
|
||
correction_available: boolean?
|
||
correction_source: provider | postal_carrier | manual | unknown
|
||
issues:
|
||
- string
|
||
```
|
||
|
||
Address quality may be emitted as diagnostics and may update a contact registry, but it should not by itself create coordination result success.
|
||
|
||
## 27. Channel Health
|
||
|
||
`hybridmail-connect` SHOULD expose hybrid-mail channel health.
|
||
|
||
```yaml
|
||
HybridmailChannelHealth:
|
||
provider_name: string
|
||
provider_account_ref: string?
|
||
status: healthy | degraded | failing | unknown
|
||
authentication_status: valid | expired | missing | insufficient | unknown
|
||
upload_status: healthy | degraded | unavailable | unknown
|
||
validation_status: healthy | degraded | unavailable | unknown
|
||
production_status: healthy | delayed | unavailable | unknown
|
||
postal_handover_status: healthy | delayed | unavailable | unknown
|
||
webhook_status: healthy | degraded | unavailable | not_supported | unknown
|
||
cutoff_status: before_cutoff | after_cutoff | no_production_day | unknown
|
||
known_degradations:
|
||
- string
|
||
```
|
||
|
||
Health-related normalized events:
|
||
|
||
```text
|
||
system.provider.degraded
|
||
system.provider.unavailable
|
||
system.adapter.health_changed
|
||
```
|
||
|
||
## 28. Security Requirements
|
||
|
||
`hybridmail-connect` MUST:
|
||
|
||
* protect provider credentials
|
||
* protect uploaded payloads and document references
|
||
* support secure transport to providers
|
||
* preserve idempotency
|
||
* avoid duplicate physical sends for repeated idempotency keys
|
||
* validate provider webhooks where supported
|
||
* avoid logging sensitive document content
|
||
* protect postal recipient data
|
||
* support tenant/account separation where applicable
|
||
* support secure deletion or retention rules for raw payloads and previews
|
||
* clearly separate test/staging and production modes
|
||
|
||
Duplicate-send prevention is especially critical because physical mail sends cost money and may have legal/business consequences.
|
||
|
||
## 29. Privacy Requirements
|
||
|
||
`hybridmail-connect` SHOULD:
|
||
|
||
* store payload references instead of payload content where possible
|
||
* support metadata-only mode
|
||
* support masking of postal addresses
|
||
* support raw event redaction
|
||
* support configurable retention of documents, previews, and raw events
|
||
* avoid unnecessary storage of print payloads after submission
|
||
* separate operational diagnostics from coordination evidence
|
||
* support deletion or anonymization workflows where legally possible
|
||
* document provider-side retention limitations
|
||
|
||
## 30. Reliability Requirements
|
||
|
||
`hybridmail-connect` MUST support:
|
||
|
||
* idempotent submit requests
|
||
* duplicate webhook event detection
|
||
* out-of-order event handling
|
||
* late return-mail events
|
||
* late delivery-confirmation events
|
||
* retryable upload failures
|
||
* non-retryable validation failures
|
||
* provider timeout handling
|
||
* provider polling fallback where webhooks are unavailable
|
||
* correlation preservation
|
||
* dead-letter handling for unprocessable events
|
||
* batch partial-failure handling
|
||
|
||
Late events MUST be preserved.
|
||
|
||
Example:
|
||
|
||
```text
|
||
Letter handed to postal service on Monday.
|
||
Coordination case moves to waiting state.
|
||
Return mail event arrives two weeks later.
|
||
The return event must still be recorded and emitted as negative evidence.
|
||
```
|
||
|
||
## 31. Raw Event Preservation
|
||
|
||
`hybridmail-connect` SHOULD preserve raw provider events or references to them.
|
||
|
||
```yaml
|
||
RawHybridmailEventRef:
|
||
raw_event_id: string
|
||
provider_name: string
|
||
source: api_response | webhook | polling | print_center | postal_carrier | return_mail | operator
|
||
storage_ref: string?
|
||
received_at: timestamp
|
||
redacted: boolean
|
||
```
|
||
|
||
Normalized events should reference raw event data where available:
|
||
|
||
```yaml
|
||
raw_event_ref: raw_hybridmail_event_123
|
||
```
|
||
|
||
## 32. Minimal API Surface
|
||
|
||
`hybridmail-connect` SHOULD expose a headless API.
|
||
|
||
### 32.1 Adapter Contract API
|
||
|
||
Required conceptual operations:
|
||
|
||
```text
|
||
GET /adapter/descriptor
|
||
GET /adapter/health
|
||
POST /adapter/actions
|
||
POST /adapter/events/provider
|
||
GET /adapter/events
|
||
GET /adapter/letters/{id}/timeline
|
||
GET /adapter/letters/{id}/assessment
|
||
```
|
||
|
||
The actual transport may differ, but these conceptual operations should exist.
|
||
|
||
### 32.2 Standalone API
|
||
|
||
Useful standalone operations:
|
||
|
||
```text
|
||
POST /hybridmail/letters
|
||
POST /hybridmail/batches
|
||
POST /hybridmail/letters/{id}/attachments
|
||
PUT /hybridmail/letters/{id}/options
|
||
POST /hybridmail/letters/{id}/preview
|
||
POST /hybridmail/letters/{id}/send
|
||
POST /hybridmail/letters/{id}/cancel
|
||
GET /hybridmail/letters/{id}
|
||
GET /hybridmail/letters/{id}/timeline
|
||
GET /hybridmail/letters/{id}/assessment
|
||
GET /hybridmail/letters/{id}/return-info
|
||
GET /hybridmail/letters/{id}/delivery-confirmation
|
||
GET /hybridmail/channel-health
|
||
```
|
||
|
||
## 33. Example End-to-End Flows
|
||
|
||
### 33.1 Ordinary Physical Letter
|
||
|
||
1. `coordination-engine` creates a coordination case.
|
||
2. A PDF payload is registered.
|
||
3. Policy selects hybrid mail as the delivery channel.
|
||
4. `coordination-engine` sends `delivery.submit_letter` to `hybridmail-connect`.
|
||
5. `hybridmail-connect` uploads the document to the provider.
|
||
6. Provider validates the document.
|
||
7. `hybridmail-connect` emits `payload.validation_passed`.
|
||
8. The letter is submitted for sending.
|
||
9. Provider transfers the letter for printing.
|
||
10. Print center hands the letter to the postal service.
|
||
11. `hybridmail-connect` emits `delivery.postal.handed_over`.
|
||
12. `coordination-engine` treats the participant as physically dispatched, but not necessarily as confirmed delivered unless policy accepts handover as sufficient.
|
||
|
||
### 33.2 Validation Failure and Correction
|
||
|
||
1. A PDF is uploaded.
|
||
2. Provider detects address-position or restricted-area issue.
|
||
3. `hybridmail-connect` emits `payload.validation_failed` with issue details.
|
||
4. `coordination-engine` marks the participant delivery attempt failed or action-required.
|
||
5. Policy requests correction, alternate document generation, or alternate channel.
|
||
6. Corrected payload is submitted with a new idempotency key or corrected version reference.
|
||
|
||
### 33.3 Registered Letter
|
||
|
||
1. A dunning letter is submitted with registered-mail option.
|
||
2. Provider validates and submits it.
|
||
3. Letter is handed to postal service.
|
||
4. Postal tracking events are received.
|
||
5. Delivery confirmation or return receipt event arrives.
|
||
6. `hybridmail-connect` emits `delivery.postal.delivery_confirmed`.
|
||
7. `coordination-engine` evaluates whether this satisfies the intended result.
|
||
|
||
### 33.4 Return Mail
|
||
|
||
1. Ordinary letter is handed to postal service.
|
||
2. No ordinary delivery confirmation is expected.
|
||
3. After several days or weeks, return mail is processed.
|
||
4. `hybridmail-connect` emits `delivery.postal.return_received`.
|
||
5. `coordination-engine` reopens, annotates, or fails the participant delivery state depending on policy.
|
||
|
||
### 33.5 Bulk Mailing
|
||
|
||
1. `coordination-engine` creates a batch delivery case.
|
||
2. `hybridmail-connect` submits a bulk/serial set of letters.
|
||
3. Some letters pass validation, others fail.
|
||
4. Per-letter evidence events are emitted.
|
||
5. `coordination-engine` aggregates participant states and avoids treating batch acceptance as universal success.
|
||
|
||
## 34. Provider Implementation Guidance
|
||
|
||
The first real provider flavor SHOULD be selected based on:
|
||
|
||
* API documentation availability
|
||
* upload and validation quality
|
||
* status granularity
|
||
* webhook support
|
||
* preview support
|
||
* return-mail support
|
||
* registered-letter support
|
||
* staging/sandbox support
|
||
* idempotency or duplicate prevention support
|
||
* cost and operational availability
|
||
* alignment with the first coordination scenario
|
||
|
||
The implementation SHOULD avoid hardcoding provider semantics into the core hybrid-mail model.
|
||
|
||
Implementation mapping should follow:
|
||
|
||
```text
|
||
Provider API/status/webhook
|
||
→ hybridmail-native event
|
||
→ HybridmailEvidenceAssessment
|
||
→ EvidenceEvent for coordination-engine
|
||
```
|
||
|
||
## 35. Message Stream / Product Separation
|
||
|
||
`hybridmail-connect` SHOULD support separate configurations for different purposes.
|
||
|
||
Recommended streams:
|
||
|
||
```text
|
||
transactional_letters
|
||
legal_or_high_assurance_letters
|
||
registered_letters
|
||
invoices
|
||
dunning
|
||
payroll
|
||
marketing_mailings
|
||
test
|
||
```
|
||
|
||
Steparation may affect:
|
||
|
||
* provider account
|
||
* sender identity
|
||
* billing account
|
||
* postal product
|
||
* print options
|
||
* return-mail handling
|
||
* retention policy
|
||
* production cutoff
|
||
* review/approval workflow
|
||
* evidence requirements
|
||
|
||
## 36. Legal and Compliance Disclaimer
|
||
|
||
`hybridmail-connect` does not by itself provide legal proof of notice, acceptance, signature, payment, or contract closure.
|
||
|
||
It provides evidence from the hybrid-mail production and postal dispatch chain.
|
||
|
||
Scenario-specific applications and `coordination-engine` policies may combine hybrid-mail evidence with registered-mail evidence, return-mail evidence, portal evidence, payment evidence, signature evidence, archive evidence, or manual evidence.
|
||
|
||
The adapter MUST avoid naming technical postal events in ways that imply legal success unless the event type is explicitly scoped.
|
||
|
||
Use:
|
||
|
||
```text
|
||
delivery.postal.handed_over
|
||
delivery.postal.delivery_confirmed
|
||
delivery.postal.return_received
|
||
```
|
||
|
||
Avoid:
|
||
|
||
```text
|
||
recipient_legally_notified
|
||
human_read_confirmed
|
||
contract_notice_completed
|
||
```
|
||
|
||
## 37. MVP Scope
|
||
|
||
The first useful version of `hybridmail-connect` should implement:
|
||
|
||
1. Adapter descriptor.
|
||
2. Provider flavor descriptor.
|
||
3. Adapter health endpoint.
|
||
4. `delivery.submit_letter`.
|
||
5. Idempotent submit request handling.
|
||
6. Simulated provider or one real provider flavor.
|
||
7. Letter, document, attempt, and recipient records.
|
||
8. Basic validation result mapping.
|
||
9. Basic print/shipping option mapping.
|
||
10. Basic status polling or webhook ingestion.
|
||
11. Evidence event generation.
|
||
12. Letter timeline.
|
||
13. Hybrid-mail evidence assessment.
|
||
14. Mapping to AdapterInterfaceSpecification.md v1.0.
|
||
|
||
### MVP Required Hybrid-Mail Events
|
||
|
||
```text
|
||
delivery.payload.submitted
|
||
delivery.payload.accepted
|
||
delivery.payload.rejected
|
||
payload.validation_passed
|
||
payload.validation_failed
|
||
delivery.payload.available
|
||
delivery.production.started
|
||
delivery.production.completed
|
||
delivery.postal.handed_over
|
||
delivery.postal.undeliverable
|
||
delivery.postal.return_received
|
||
delivery.postal.status_unknown
|
||
system.provider.degraded
|
||
system.provider.unavailable
|
||
```
|
||
|
||
### MVP Acceptance Criteria
|
||
|
||
The MVP is acceptable when it can:
|
||
|
||
1. Accept a coordination-compatible hybrid-mail submit request.
|
||
2. Dispatch or simulate a PDF letter submission.
|
||
3. Preserve correlation and idempotency.
|
||
4. Prevent duplicate physical sends for duplicate idempotency keys.
|
||
5. Record provider acceptance separately from validation.
|
||
6. Classify validation failure as strong negative payload evidence.
|
||
7. Classify postal handover as strong dispatch evidence but not proof of human awareness.
|
||
8. Classify ordinary no-final-status cases as unresolved rather than success.
|
||
9. Record return mail as strong negative evidence.
|
||
10. Provide a letter timeline.
|
||
11. Provide a hybrid-mail evidence assessment.
|
||
12. Integrate with coordination-engine without overclaiming success.
|
||
|
||
## 38. Future Extensions
|
||
|
||
Potential future capabilities:
|
||
|
||
* multi-provider routing
|
||
* provider failover
|
||
* cost optimization by product/provider
|
||
* print-preview comparison
|
||
* PDF/A conversion support
|
||
* advanced address extraction
|
||
* address correction feedback loop
|
||
* return-mail scan ingestion
|
||
* registered-mail evidence archive
|
||
* delivery-confirmation document archive
|
||
* production SLA monitoring
|
||
* cutoff-aware scheduling
|
||
* country-specific postal product model
|
||
* automated correction workflows
|
||
* physical plus digital fallback patterns
|
||
* duplicate-content detection
|
||
* batch campaign analytics
|
||
* monthly journal / billing export integration
|
||
* print layout linting
|
||
* DIN 5008 address-window validation
|
||
* provider certification test suites
|
||
|
||
## 39. Non-Goals
|
||
|
||
`hybridmail-connect` is not:
|
||
|
||
* a document authoring system
|
||
* a PDF renderer by default
|
||
* a postal carrier
|
||
* a legal notice system by itself
|
||
* a signature system
|
||
* a payment system
|
||
* a CRM
|
||
* a full workflow engine
|
||
* the owner of coordination case success
|
||
|
||
It may integrate with such systems or be used by them.
|
||
|
||
## 40. Summary
|
||
|
||
`hybridmail-connect` models hybrid mail as a physical delivery channel initiated through digital submission.
|
||
|
||
Its job is to:
|
||
|
||
* submit PDF or print-ready documents
|
||
* validate hybrid-mail payloads
|
||
* map provider-specific print and shipping options
|
||
* track production and postal handover
|
||
* process return-mail and undeliverable evidence
|
||
* normalize registered or delivery-confirmation evidence
|
||
* expose document, letter, batch, and channel diagnostics
|
||
* integrate cleanly with `coordination-engine`
|
||
|
||
The key rule is:
|
||
|
||
> Hybrid-mail events are physical production and postal-chain evidence, not automatic coordination result satisfaction. hybridmail-connect reports hybrid-mail facts and uncertainty. coordination-engine evaluates intended results.
|
||
|