Engineering•2 min read

Preventing Duplicate Transactional Emails with Idempotency Keys

Learn how to use idempotency keys with Piisend's REST API to prevent duplicate transactional email sends. Ensure retry safety and a consistent user experience even with network issues or client-side retries.

Preventing Duplicate Transactional Emails with Idempotency Keys

Section 1

The Silent Threat of Duplicate Transactional Emails

In distributed systems, network glitches or client-side retry logic can inadvertently lead to the same request being sent multiple times. For transactional emails like OTP verification, password resets, or order confirmations, this can result in users receiving identical emails, causing confusion and a poor experience. Preventing these duplicate sends is crucial for maintaining trust and system reliability. This is where the concept of idempotency becomes invaluable.

Section 2

Ensuring Retry Safety with Piisend's Idempotency Keys

Piisend's REST API supports idempotency through the Idempotency-Key header. By including a unique, client-generated key with each POST /api/v1/emails request, you can safely retry without duplicate sends. If Piisend receives the same key within the idempotency window, it returns the original response and does not send again.

bash
1curl -sS -X POST https://api.piisend.com/api/v1/emails \
2 -H "Authorization: Bearer YOUR_API_KEY" \
3 -H "Content-Type: application/json" \
4 -H "Idempotency-Key: receipt:order-123" \
5 -d '{
6 "to": ["user@example.com"],
7 "subject": "Your order confirmation",
8 "html": "<p>Thank you for your order #123. It will be shipped soon.</p>",
9 "text": "Thank you for your order #123. It will be shipped soon."
10 }'

Section 3

Generating Robust Idempotency Keys for Transactional Emails

The effectiveness of idempotency relies on generating unique and deterministic keys. For transactional email operations, a good practice is to combine a unique identifier from your system (e.g., order ID, user ID, session ID) with the specific action being performed (e.g., order-confirmation, password-reset). This ensures that retries for the same logical operation consistently use the same idempotency key, while different operations or different instances of the same operation get distinct keys. This pattern provides robust retry safety for your email sends.

python
1import os
2import httpx
3
4def send_idempotent_email(to_email, subject, text, operation_id, operation_type):
5 idempotency_key = f"{operation_type}:{operation_id}"
6 response = httpx.post(
7 "https://api.piisend.com/api/v1/emails",
8 headers={
9 "Authorization": f"Bearer {os.environ['PIISEND_API_KEY']}",
10 "Idempotency-Key": idempotency_key,
11 },
12 json={
13 "to": [to_email],
14 "subject": subject,
15 "text": text,
16 },
17 timeout=30.0,
18 )
19 response.raise_for_status()
20 return response.json()
21
22# send_idempotent_email("buyer@example.com", "Your receipt", "Here is your receipt.", "ORD12345", "receipt")

Section 4

Understanding Piisend's Idempotency Window Behavior

Piisend maintains an idempotency window, typically 24 hours, during which it will recognize and de-duplicate requests with the same Idempotency-Key. If you retry a request with the identical key within this window, Piisend will return the original response (including the email status) without attempting to send the email again. After this window expires, a subsequent request with the same key will be treated as a new, distinct request. This mechanism is crucial for ensuring retry safety and preventing duplicate sends while allowing for legitimate new sends of similar operations over time, such as a new password reset request after a day.

Start sending

Ship transactional email in minutes

Create an API key, verify a domain, and send your first message with Piisend.