
Keep retries tied to the same message
A logical email submission has an identity that can be reused when delivery is retried. Supported providers can recognize that identity, reducing accidental duplicate submissions after an uncertain response.
An explicit resend with a new action token remains a new message.
Example — Retry an invitation submission
The first provider response is uncertain. A retry keeps the original submission identity; an administrator’s later resend uses the newly issued invitation token and a new identity.
For engineers
Preserve the logical submission across attempts
For token-backed operation emails, the dispatcher derives an identity from the committed source, notification, template and recipient. The derivation does not place the raw recipient address in an idempotency header:
Selected from notifications-dispatcher.backend.service.ts; surrounding module configuration is omitted.
export function deriveEmailNotificationSubmissionId(
sourceId: string,
notificationIdentifier: string,
templateRef: string,
recipientIdentity: { email?: string; userId?: string },
): string {
return createHash('sha256')
.update(JSON.stringify({
sourceId,
notificationIdentifier,
templateRef,
recipientIdentity,
}))
.digest('hex');
}
The queued path persists a submissionId for each item. Providers that declare idempotency support receive the identity through their adapter-specific header or payload field. A custom sender must reuse an existing logical identity when retrying the same submission rather than minting a fresh one on each attempt.
Let the provider contract decide retry safety
The sender classifies confirmed acceptance, rejection and ambiguous transport outcomes. Batch retry uses the result’s retryable decision. A stable identity alone cannot guarantee duplicate prevention on a provider without the corresponding contract, nor guarantee inbox delivery.
RESEND deliberately mints a replacement token and represents a new logical message. Do not reuse the old submission identity for that new content. Token revocation and provider acceptance are separate: withdrawing a token cannot recall an email already accepted by the provider.