Prevent duplicate agent emails when a request times out
Persist a send identity before submission and separate definitive failures from uncertain provider outcomes.
Build status tracking around actual event evidence rather than treating a successful send response as a read receipt.
An email can pass your application’s review, pass Lupin policy checks and be accepted by an outbound provider without reaching the recipient’s inbox. Those are separate boundaries. email.sent means the outbound provider accepted the send. Current outbound adapters do not wire recipient delivery receipts, so email.delivered should not be assumed to follow every accepted message. Use precise interface language such as accepted for sending when that is the known outcome. Avoid sent and read checkmarks that imply evidence your integration never received.
A message can be blocked before a provider is called. Missing permissions, unverified-workspace recipient rules and hierarchical allow/block lists are different causes. List rejection returns a rejected result and an email.rejected event, while a configuration failure can report mail_not_configured. Save the structured error code with the attempt so an operator knows whether to review authority, recipient policy or provider setup. Repeating a policy-rejected request is not a delivery retry, and changing the recipient silently can violate the action the human actually approved.
A definitive provider rejection establishes that this request was not accepted for delivery; an uncertain network outcome does not. Preserve the same operation key and recorded reservation when the system cannot establish the provider result. Do not classify a timeout as bounced, because a bounce is a separate mail feedback event. Keep unresolved submissions visible and reconcile them before issuing another send. An application that turns every failed HTTP response into safe-to-retry can create duplicate emails precisely when the provider accepted the first one.
Lupin exposes event types for bounced, complained, rejected and opened states as well as sent and delivered. Domain feedback configuration matters for bounce and complaint handling. Open tracking injects a pixel and fires email.opened once on the first observed open, but fetching a pixel does not prove a particular human read or understood the message. Remote-image blocking, automated fetching and client behavior limit what that signal can establish. Keep tracking disabled unless the workflow needs it, and describe observed telemetry rather than inventing a recipient’s attention or intent.
Record each verified event with its event ID, resource identity and timestamp, deduplicate it, and retain the source of the state transition. A later event should update the appropriate dimension rather than erase earlier evidence: accepted then bounced is a useful history. Do not require an unsupported delivery event before considering an accepted submission operationally complete, but keep recipient delivery explicitly unconfirmed. Your next step is a synthetic status fixture covering local rejection, provider acceptance, uncertainty, bounce and open observation, then check every user-facing phrase against the evidence it actually represents.
A useful case record can hold submission_state and recipient_feedback separately. A received bounce should not erase the accepted submission evidence that preceded it. Similarly, an opened label should not force an unsupported delivered receipt into the record. Keeping these dimensions explicit makes retries and support investigations easier to explain without manufacturing intermediate events.
Reviewed against checked-in Lupin API handlers and documentation. Example requests were not executed against live providers.
Prepared with AI assistance by Lupin editorial. How we research and maintain these guides.