guida · api email

Come dovrebbe implementare un'API email in sicurezza un team di prodotto?

Implementa un'API email come flusso asincrono e soggetto a permessi, non come chiamata diretta da un modulo al provider. Autentica il chiamante, conferma che il tenant possieda un dominio From verificato, convalida il messaggio e controllane le dimensioni, assegna un ID di job applicativo stabile, metti in coda una sola volta ed esegui l'invio da un worker. Registra l'ID del messaggio del provider al momento dell'accettazione, acquisisci gli eventi di consegna in modo idempotente e sopprimi i bounce permanenti e le segnalazioni di spam. Usa tentativi limitati solo quando il rischio di duplicati è sotto controllo. Tieni le credenziali lato server, riduci al minimo i dati dei messaggi nei log e distingui tra accettazione da parte dell'API, consegna al server di posta e arrivo in inbox.

Definisci il confine dell'API prima di scegliere un provider

Un'API email dovrebbe esporre l'intento applicativo senza far trapelare ogni dettaglio del provider nel codice del prodotto. Definisci risorse per messaggi, domini di invio, chiavi API, eventi e soppressioni. Decidi quali campi possono controllare i chiamanti, tra cui From, To, Reply-To, oggetto, testo, HTML e una breve allowlist di intestazioni. Rifiuta le intestazioni di trasporto fornite dal chiamante che potrebbero entrare in conflitto con la firma o l'instradamento del provider. Tratta l'invio come una scrittura con conseguenze: la risposta dovrebbe identificare una risorsa messaggio dell'applicazione e il suo stato attuale, senza lasciar intendere un esito nella casella di posta. Tieni account del provider, regione, configuration set e identificatori di trasporto dietro un adapter. Questo confine rende possibile la migrazione tra provider e offre un punto stabile per i controlli di autorizzazione, conservazione e anti-abuso.

Autentica i chiamanti e autorizza ogni dominio mittente

Conserva le chiavi API solo come hash unidirezionali e mostra il segreto completo una sola volta. Assegna a ogni chiave un workspace proprietario, uno stato, una data di creazione e un percorso di revoca; aggiungi ambiti più ristretti quando un'integrazione deve solo inviare o solo leggere gli eventi. L'autenticazione stabilisce chi ha presentato una credenziale, mentre l'autorizzazione decide se quel soggetto può usare il dominio From e la risorsa messaggio richiesti. Controlla la proprietà del dominio a ogni invio, anche sugli endpoint batch, invece di fidarti di un identificatore di dominio fornito dal client. Richiedi la verifica del provider prima di abilitare il traffico di produzione. Non inserire mai credenziali del provider o chiavi API del workspace nel JavaScript del browser, nelle query string, negli analytics o nei messaggi di errore. In un'API multi-tenant, l'autorizzazione a livello di oggetto è particolarmente importante per gli identificatori di messaggi, eventi, soppressioni, inbox e domini.

Verifica il dominio e allinea l'autenticazione

Un dominio di invio richiede più di un flag nel database. Completa il controllo di proprietà del provider e pubblica i record DKIM richiesti. SPF autorizza gli host per l'identità SMTP MAIL FROM o HELO, mentre DKIM associa un dominio di firma a una firma crittografica del messaggio. DMARC valuta se un identificatore SPF o DKIM superato con successo è allineato con il dominio From visibile secondo RFC 5322 e permette al proprietario del dominio di pubblicare una policy di gestione e di reporting. Se un dominio ha già un record SPF, unisci il meccanismo richiesto al record esistente; RFC 7208 stabilisce che un dominio non deve pubblicare più record che portino alla selezione di più di un record SPF. Introduci una policy DMARC più restrittiva solo dopo che messaggi controllati e report aggregati mostrano che ogni mittente legittimo è allineato. L'autenticazione riduce l'uso non autorizzato del dominio, ma non garantisce l'arrivo in inbox.

Convalida la struttura del messaggio e riduci al minimo l'input accettato

RFC 5322 definisce un messaggio Internet come una serie di campi di intestazione seguiti da un corpo opzionale, mentre le specifiche MIME estendono il contenuto oltre il testo semplice. Un'API può nascondere la maggior parte dei dettagli del formato di trasmissione pur continuando ad applicarli. Normalizza gli array di destinatari, limita il numero di destinatari e la dimensione codificata totale, richiedi almeno un corpo di testo o HTML e convalida gli indirizzi senza pretendere che la sintassi dimostri l'esistenza della casella. Rimuovi i caratteri di ritorno a capo e di avanzamento riga dai campi che diventano intestazioni. Genera il Message-ID oppure lascia che lo faccia il provider; non riutilizzarlo come ID del job applicativo, perché una nuova versione del messaggio può legittimamente ricevere un nuovo identificatore. Consenti solo le intestazioni personalizzate documentate, rifiuta i duplicati dei campi protetti e renderizza i template prima dell'invio al provider, così che le variabili mancanti falliscano in uno stato applicativo controllato.

Metti in coda una sola volta e usa identificatori applicativi stabili

Una richiesta dell'utente dovrebbe creare un unico job di messaggio persistente all'interno di una transazione, dopodiché un worker dovrebbe eseguire la chiamata al provider. Assegna al job un identificatore stabile e registra un'impronta della richiesta o una chiave di idempotenza fornita dal chiamante, quando il contratto lo prevede. HTTP definisce POST come non idempotente per impostazione predefinita e sconsiglia i nuovi tentativi automatici, a meno che il client non sappia che l'operazione è di fatto idempotente o che la richiesta originale non è stata applicata. Per le email questo conta, perché un timeout può verificarsi dopo che il provider ha accettato il messaggio ma prima che il worker abbia ricevuto la risposta. In caso di errore ambiguo, riconcilia prima lo stato del job salvato e del provider invece di creare un nuovo invio. Usa un pattern outbox quando lo stato applicativo e la pubblicazione in coda devono avanzare insieme, e applica un vincolo di unicità attorno al confine di idempotenza.

Progetta i nuovi tentativi in base alle classi di errore

Separa convalida, autorizzazione, throttling, rifiuto del provider, errore di trasporto temporaneo ed errore di consegna al destinatario. Un input non valido e un dominio From non autorizzato devono fallire senza nuovi tentativi. I limiti di frequenza (rate limit) del provider e gli errori temporanei del servizio possono essere ritentati con backoff esponenziale limitato, jitter, un tetto di tentativi e un visibility timeout della coda più lungo della scadenza della richiesta del worker. Un timeout di rete ambiguo richiede una riconciliazione che tenga conto dei duplicati, non una nuova richiesta incondizionata. SMTP distingue già tra risposte temporanee 4xx e permanenti 5xx, ma un'applicazione che usa l'API di un provider dovrebbe seguire la semantica degli errori documentata da quel provider. Sposta i job esauriti in uno stato di dead letter consultabile e conserva il motivo ripulito da dati sensibili. Non ritentare un bounce permanente del destinatario come se fosse un'interruzione dell'API, e non trasformare una segnalazione di spam in un altro tentativo di invio.

Registra l'accettazione e acquisisci gli eventi di consegna

Conserva l'identificatore del messaggio del provider immediatamente dopo l'accettazione e mappalo all'ID messaggio dell'applicazione. Gli eventi del provider possono quindi aggiornare la risorsa corretta anche quando una segnalazione di spam oscura i dettagli del destinatario. Amazon SES, ad esempio, distingue un invio riuscito dalla consegna al server di posta del destinatario e può pubblicare eventi di consegna, bounce, segnalazione di spam, rifiuto, ritardo di consegna, errore di rendering, apertura e clic. Verifica l'autenticità dei webhook tramite il meccanismo documentato dal provider, convalida lo schema dell'evento, deduplica tramite un identificatore di evento del provider o un fingerprint deterministico e consenti consegne ripetute dello stesso evento senza ripetere effetti collaterali. Archivia i payload raw solo quando necessario, cifrati, con accesso controllato e conservazione limitata. Lo stato normalizzato deve distinguere esiti accettato, consegnato al server, rimbalzato, con segnalazione di spam, ritardato, rifiutato e soppresso.

Rendi la soppressione un controllo al momento dell'invio

Un record di soppressione va controllato prima di ogni invio al provider, non solo mostrato in una dashboard. Gli indirizzi in bounce permanente e le segnalazioni di spam di norma richiedono la soppressione; i ritardi di consegna temporanei richiedono una policy diversa. Definisci l'ambito della soppressione in modo consapevole. Una lista a livello di account può proteggere la reputazione condivisa, ma può far sì che l'esito di un destinatario di un tenant blocchi un altro tenant. Una lista con ambito limitato al tenant riduce questo accoppiamento, ma richiede comunque un livello di sicurezza della piattaforma e di gestione degli abusi. Registra il motivo, l'evento di origine, il tenant, la data di creazione e un percorso di rimozione controllato. Rimuovere una soppressione dovuta a una segnalazione di spam o a un bounce permanente ha conseguenze e dovrebbe richiedere una revisione deliberata e prove che l'indirizzo sia valido e che il destinatario si aspetti il messaggio. Evita di copiare gli indirizzi raw dei destinatari nei log generici o negli esperimenti: lo storage operativo può applicare la policy di invio, mentre gli analytics usano conteggi aggregati.

Proteggi gli invii batch e i flussi aziendali sensibili

Un endpoint batch moltiplica l'impatto di un errore di autorizzazione o di convalida. Applica a ogni elemento gli stessi controlli su proprietà del dominio, soppressione, dimensioni e contenuto, imponi una lunghezza massima rigorosa del batch e restituisci risultati per singolo elemento senza esporre dati di altri tenant. I limiti di frequenza dovrebbero esistere a livello di credenziale, workspace, dominio e provider, con controlli separati per i picchi e per il volume su finestra mobile. Un singolo limite globale di richieste al secondo non basta, perché una sola richiesta può contenere molti destinatari. Negli strumenti guidati da agenti, richiedi una conferma esplicita prima di inviare un batch ad alto impatto. Separa i permessi transazionali da quelli di marketing quando le relative regole di consenso e operative differiscono. Monitora crescite anomale dei destinatari, domini rifiutati ripetutamente, variazioni elevate di bounce o segnalazioni di spam e la creazione rapida di chiavi. I limiti di frequenza aiutano la sicurezza, ma non sostituiscono autenticazione, autorizzazione a livello di oggetto, consenso verificato e risposta agli abusi.

Testa i percorsi di errore prima della produzione

Usa i simulatori del provider o caselle controllate per testare accettazione, consegna al server destinatario, hard bounce, segnalazione di spam, ritardo, dominio non valido, chiave revocata, throttling, timeout del provider, webhook duplicato e riconsegna dalla coda. Verifica che la stessa chiave di idempotenza crei un solo messaggio applicativo, che un evento rieseguito non produca effetti collaterali duplicati e che un tenant non possa leggere né inviare con il dominio o l'ID messaggio di un altro tenant. Esamina un messaggio realmente ricevuto per controllare From, Return-Path, DKIM, SPF, allineamento DMARC, rendering di testo e HTML, comportamento della disiscrizione dove applicabile e link. Esegui test di carico sulla coda restando sotto i limiti approvati dal provider e verifica il backpressure invece di aggirarlo. Aggiungi allarmi su età della coda, tentativi esauriti, errori di acquisizione degli eventi, margine sulle quote, variazioni di bounce e segnalazioni di spam e callback del provider mancanti. Una checklist di lancio dovrebbe indicare un responsabile per ogni avviso e ogni azione di ripristino.

Applica il pattern con SendHQ con attenzione

SendHQ fornisce chiavi bearer con ambito limitato al workspace, controlli del dominio From verificato, creazione di messaggi singoli e batch, inbox in entrata, eventi dei messaggi e risorse di soppressione. Queste funzionalità supportano l'architettura di questa guida: conserva la chiave lato server, crea una risorsa messaggio, mantienine l'ID e leggi gli eventi successivi anziché trattare la risposta iniziale come consegna finale. Indipendentemente dalla piattaforma, chi chiama resta responsabile dei destinatari previsti, della posta lecita e attesa, dell'accuratezza dei contenuti e dell'attenta approvazione degli invii con conseguenze.

Domande frequenti

Un'API email dovrebbe inviare in modo sincrono dalla richiesta web?

Di solito no. Crea un messaggio applicativo persistente e mettilo in coda, poi lascia che sia un worker a chiamare il provider. In questo modo isoli la latenza, supporti tentativi limitati e semplifichi la riconciliazione degli esiti ambigui del provider.

Come evito email duplicate quando una richiesta va in timeout?

Usa un ID di job applicativo stabile e un confine di idempotenza con un vincolo di unicità. In caso di timeout ambiguo, riconcilia il job esistente prima di effettuare un altro invio al provider con una nuova identità.

Una risposta positiva dell'API email significa che il messaggio è stato consegnato?

No. Di norma indica che l'API o il provider ha accettato la richiesta. Usa gli eventi successivi per distinguere dall'accettazione iniziale la consegna al server destinatario, il bounce, la segnalazione di spam, il ritardo, il rifiuto e la soppressione.

Quali record DNS servono a un'API email?

I record esatti dipendono dal provider, ma l'invio in produzione richiede di solito la verifica del dominio e DKIM, oltre a una strategia SPF corretta e a una policy DMARC allineata con i flussi di invio legittimi.

Le chiavi API vanno salvate nel codice del browser?

No. Tieni le credenziali del workspace e del provider in un archivio di segreti lato server, salva come hash le chiavi API applicative dove possibile, mostra i segreti completi una sola volta e prevedi percorsi rapidi di revoca e rotazione.

Come dovrebbe gestire i bounce permanenti un'API email?

Normalizza l'evento del provider, associalo al messaggio applicativo e sopprimi i futuri invii di routine a quel destinatario entro l'ambito previsto. La rimozione dovrebbe essere deliberata e supportata da prove.

Fonti