Salta ai contenuti

Tentativi e idempotenza

Le reti falliscono – soprattutto su mobile. Tutti gli SDK di Frontmail ripetono automaticamente le richieste non riuscite, e lo fanno in sicurezza: un invio ripetuto non produce mai un’email duplicata né un doppio addebito.

Situazione Ripetuto?
Errore di rete (offline, DNS, connessione interrotta) ✓
Timeout (timeoutMs, predefinito 15 s per tentativo) ✓
Risposte 5xx ✓
429 rate_limited ✓ – attende Retry-After (se è di 60 s o meno)
Errori 4xx di validazione, autenticazione, origine, CAPTCHA ✗ – ripetere non servirebbe
Blocchi lato client (blockHeadless, blockList, limitRate) ✗

Criterio predefinito: 3 nuovi tentativi dopo il primo, backoff esponenziale a partire da 300 ms con full jitter, al massimo 10 s tra un tentativo e l’altro. Configuralo con l’opzione retry:

init({ publicKey: 'pk_4f2a…', retry: { retries: 5, baseDelayMs: 500, maxDelayMs: 20_000 } });
init({ publicKey: 'pk_4f2a…', retry: false }); // disattiva

Ogni send() logico riceve un UUID casuale come Idempotency-Key, e tutti i tentativi ripetuti di quell’invio riutilizzano la stessa chiave. Sul server, Frontmail ricorda le chiavi per 24 ore:

  • la stessa chiave con lo stesso body restituisce la risposta originale (stesso message_id) senza inviare di nuovo,
  • la stessa chiave con un body diverso fallisce con 409 idempotency_conflict.

Quindi, se il primo tentativo ha effettivamente raggiunto Frontmail ma la risposta è andata persa, il nuovo tentativo riceve semplicemente il risultato originale.

Passa una chiave esplicita quando è il fattore scatenante stesso a potersi ripetere – un webhook consegnato due volte, un job che riparte, un utente che invia un modulo due volte in due schede:

// @frontmail/node
await frontmail.send({ templateId: 'tpl_receipt', params, idempotencyKey: `receipt-${order.id}` });
// @frontmail/browser – le opzioni sono l’ultimo argomento
await send('svc_01J9…', 'tpl_receipt', params, { idempotencyKey: `receipt-${order.id}` });

Le chiavi possono avere fino a 255 caratteri. Usa una nuova chiave per ogni email distinta – riutilizzarne una per un’email diversa restituisce un errore invece di inviarla.

Con l’API REST, invia tu l’header:

Finestra del terminale
curl https://api.frontmail.dev/v1/send \
-H 'Idempotency-Key: receipt-A-1042' \
-H 'Authorization: Bearer sk_…' \
-H 'Content-Type: application/json' \
-d '{ "template_id": "tpl_receipt", "template_params": { "order_id": "A-1042" } }'

Per gli invii in batch, imposta idempotencyKey (idempotency_key nell’API REST) per ogni messaggio.

Una volta che l’API ha restituito 202, i tentativi di recapito sono compito di Frontmail: il mittente ripete con backoff gli errori temporanei del provider, passa al servizio di riserva in caso di errori di autenticazione o permanenti e mette in attesa i messaggi quando un servizio non funziona. Il tuo codice non deve fare nulla – se serve, controlla il risultato con getStatus() o nella Cronologia.