feat: add support for Message-ID handling and idempotency in send API#3488
feat: add support for Message-ID handling and idempotency in send API#3488max-kuklin wants to merge 1 commit intopostalserver:mainfrom
Conversation
|
sounds exciting, thanks for your efforts! |
|
Hi @adamcooke, do you think this has a chance to be included in the next release? If I can help you in any way please let me know 🙏 |
|
EDIT: i made some incorrect suggestions for code changes here, mixed up some commits. View history for details. |
|
@quaaantumdev it sounds like you are referencing a different idempotency design pattern (likely Stripe-style idempotency keys with database locking) rather than Message-ID based deduplication approach. The fixes you suggest would require implementing an entirely new architecture that doesn't currently exist in this PR (including the files you propose to fix). |
|
@max-kuklin sorry max, i was just in desprite search for idempotency with postal and must have mixed up this pull request with some other commit, solving the same issue in a different way. I actually prefer your solution, would be great to see this RP merged for a future release. |
Adds support for: - Custom Message-IDs via message_ids parameter in /api/v1/send/message - Idempotency detection based on Message-ID for duplicate prevention - Message-ID extraction from raw emails in /api/v1/send/raw - RFC 5322 format validation for Message-IDs Cherry-picked from postalserver/postal PR postalserver#3488 Co-authored-by: max-kuklin <max-kuklin@users.noreply.github.com> Co-authored-by: openhands <openhands@all-hands.dev>
|
This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days. |
|
Hi @adamcooke just following up, do you think we could merge this? I would really like to avoid maintaining a fork and rather help upstream project 🙏 |
Add Idempotency Support for Email Sending APIs
Summary
We send a large volume of emails through the Postal API with instances installed on remote ISPs. Network hiccups are inevitable in this setup, causing API requests to timeout or fail intermittently. Without idempotency, retrying these failed requests results in duplicate emails being sent to recipients.
This PR implements idempotency for the API endpoints (
/api/v1/send/messageand/api/v1/send/raw) using RFC 5322 Message-ID headers. Clients can now safely retry failed requests without sending duplicate emails, using client-defined Message-IDs for precise control over deduplication.Changes
API Enhancements
/api/v1/send/messageendpoint:message_idsparameter accepts a hash mapping recipient email addresses to custom Message-IDsmessage_idandexistingflag for each recipient in the response/api/v1/send/rawendpoint:message_idandexistingflag for each recipient in the responseResponse Format
When Message-IDs are provided or detected:
{ "status": "success", "data": { "messages": { "user@example.com": { "id": 123, "token": "abc123", "message_id": "<unique-id@example.com>", "existing": false } } } }Validation
local-part@domain(angle brackets optional in API but stripped for storage)InvalidMessageIDerror with clear format requirementsImplementation Details
OutgoingMessagePrototypeenhanced withmessage_idsattribute, validation logic, and per-recipient duplicate detectionSendControllerupdated to acceptmessage_idsparameter and extract Message-ID from raw email headersmessage_idcolumn (varchar 255) with partial index on first 8 charactersTesting
Comprehensive test suite with 46 passing tests (0 failures):
/messageendpoint idempotency (basic flow, per-recipient IDs, duplicates, partial duplicates, angle brackets, non-hash params)/rawendpoint idempotency (Message-ID extraction, duplicates, partial duplicates, angle brackets)Usage Examples
/messageendpoint with idempotency:/rawendpoint (automatic Message-ID extraction):Benefits
Backward Compatibility
✅ 100% Backward Compatible
message_idsparameter is optional for/messageendpoint