Stato e Ciclo di Vita dell'Email
Comprendi gli stati di status e gli eventi di tracciamento
Ogni email in Tratto ha uno status (lo stato dell'email) e eventi (cosa le è successo). Comprendi la differenza e come tracciarla.
Status vs Eventi
- Status: Lo stato attuale dell'email (
scheduled,queued,sending,sent,delivered,bounced,complained,failed,skipped,canceled) - Eventi: Record discreti di tracciamento (opened, clicked, bounced, complained)
Esempio: Un'email può avere status delivered e anche avere eventi opened, clicked, e clicked di nuovo.
Ciclo di Vita dello Status dell'Email
Un'email progredisce attraverso questi status:
(solo con scheduledAt)
scheduled ──→ queued ──→ sending ──→ sent ──→ delivered
│ │ │ │ │
▼ ▼ ▼ └────┬─────┘
canceled skipped failed ▼
skipped failed bounced, complainedUn'email inviata senza scheduledAt parte da queued. Aperture, clic e
disiscrizioni sono eventi, non status: non cambiano mai lo
status.
Definizioni dello Status
| Status | Descrizione |
|---|---|
scheduled | L'email è programmata per una consegna futura (hai impostato scheduledAt). Passa a queued quando arriva l'ora |
queued | L'email è in coda, verrà inviata a breve (minuti) |
sending | Tratto ha preso in carico l'email e la sta consegnando al provider di posta. Dura pochi secondi |
sent | L'email è stata consegnata al server di posta, ma non ancora confermata dal server del destinatario |
delivered | Il server di posta del destinatario ha confermato la ricezione |
bounced | Il server di posta del destinatario ha rifiutato l'email |
complained | Il destinatario ha segnalato l'email come spam |
failed | Tratto non ha inviato l'email (un dominio mittente non verificato, un template non pubblicato, un allegato eliminato, un rifiuto del provider di posta, ecc.). Con l'API 0.29.0 o successiva il motivo è in failureReason: vedi Perché un'email è fallita |
skipped | Tratto non ha inviato l'email perché il destinatario si è disiscritto o è nella lista di soppressione. Non è partito niente |
canceled | Hai annullato un'email scheduled con DELETE /v1/emails/:id prima dell'invio |
GET /v1/emails?status= filtra per uno qualsiasi di questi valori, sending compreso; se ne possono combinare più separati da virgole (?status=queued,sending).
failed, bounced e complained sono definitivi: niente di quello che arriva
dopo li cambia, con l'unica eccezione qui sotto.
Quando la consegna viene interrotta
Se la consegna si interrompe mentre Tratto sta passando l'email al provider di
posta (per esempio si ferma il worker che la stava inviando), Tratto non può
sapere se il provider l'ha accettata. In quel caso l'email diventa failed e
non viene ritentata: Tratto preferisce non inviare un'email piuttosto che
inviarla due volte. L'email potrebbe comunque essere arrivata al destinatario.
Se in seguito il provider segnala una consegna, un rimbalzo o un reclamo, lo
status passa a delivered, bounced o complained.
Un'email che resta in sending per più di qualche minuto è in questa
situazione e verrà chiusa come failed quando Tratto la riprende in mano.
Perché un'email è fallita
Richiede l'API 0.29.0 o successiva.
GET /v1/emails/{id} e GET /v1/emails restituiscono failureReason su
un'email failed: un codice stabile come template_not_published,
provider_rejected o attachment_unavailable. Lo stesso codice arriva come
data.reason nell'evento webhook failed,
il cui data.error aggiunge una frase leggibile. L'elenco dei codici e il loro
significato è in Evento failed. Possono
aggiungersi codici nuovi, quindi gestisci anche i valori che non conosci. Le
email fallite prima che il campo esistesse non hanno failureReason.
interrupted è l'unico codice non definitivo: vedi
Quando la consegna viene interrotta.
Transizioni di Stato
scheduled (solo se scheduledAt è stato impostato)
├─→ canceled (DELETE /v1/emails/:id)
├─→ skipped (il destinatario si è disiscritto)
└─→ queued (è arrivata l'ora programmata)
queued
├─→ skipped (destinatario disiscritto o soppresso)
├─→ failed (l'email non può essere costruita o inviata)
└─→ sending (Tratto passa l'email al provider di posta)
├─→ failed (rifiutata dal provider, o consegna interrotta)
└─→ sent (il server di posta ha accettato l'email)
├─→ delivered (il server del destinatario conferma la consegna)
│ └─→ bounced, complained
└─→ bounced, complainedOttieni lo Status dell'Email
Recupera lo status attuale e i dettagli di un'email.
cURL
curl https://api.tratto.email/v1/emails/email_abc123 \
-H "Authorization: Bearer tratto_live_..."Node.js
const response = await fetch('https://api.tratto.email/v1/emails/email_abc123', {
headers: { 'Authorization': 'Bearer tratto_live_...' },
});
const { data } = await response.json();
console.log('Status:', data.status);
console.log('Creata:', data.createdAt);
console.log('Inviata:', data.sentAt);Python
import requests
response = requests.get(
'https://api.tratto.email/v1/emails/email_abc123',
headers={'Authorization': 'Bearer tratto_live_...'},
)
data = response.json()['data']
print(f"Status: {data['status']}")
print(f"Creata: {data['createdAt']}")PHP
$tratto = new \Tratto\Client(getenv('TRATTO_API_KEY'));
$email = $tratto->emails->get('email_abc123');
echo "Status: {$email['status']}\n";
echo "Creata: {$email['createdAt']}\n";Risposta
{
"data": {
"id": "email_abc123",
"status": "delivered",
"from": "hello@tuodominio.it",
"to": "user@example.com",
"subject": "Benvenuto!",
"createdAt": "2025-06-30T12:00:00Z",
"sentAt": "2025-06-30T12:00:05Z",
"deliveredAt": "2025-06-30T12:00:10Z",
"scheduledAt": null,
"tags": []
}
}Eventi Email
Gli eventi sono record discreti di tracciamento per quello che è successo a un'email dopo l'invio. A differenza dello status (uno stato singolo), un'email può avere molti eventi.
Tipi di Evento
| Tipo Evento | Descrizione |
|---|---|
sent | Email è stata accettata dal server di posta |
delivered | Server di posta ha confermato consegna alla mailbox del destinatario |
opened | Destinatario ha aperto l'email (tracciamento pixel) |
clicked | Destinatario ha cliccato un link nell'email |
bounced | Server di posta ha rifiutato consegna (rimbalzo hard o soft) |
complained | Destinatario ha segnalato l'email come spam |
unsubscribed | Destinatario ha cliccato il link di annullamento iscrizione |
failed | L'email non è stata inviata; data.reason e data.error dicono perché (richiede l'API 0.29.0 o successiva) |
Ottieni Eventi Email
Recupera tutti gli eventi per un'email specifica.
cURL
curl https://api.tratto.email/v1/emails/email_abc123/events \
-H "Authorization: Bearer tratto_live_..."Node.js
const response = await fetch('https://api.tratto.email/v1/emails/email_abc123/events', {
headers: { 'Authorization': 'Bearer tratto_live_...' },
});
const { data } = await response.json();
data.forEach(event => {
console.log(`${event.type} at ${event.occurredAt}`);
});Python
import requests
response = requests.get(
'https://api.tratto.email/v1/emails/email_abc123/events',
headers={'Authorization': 'Bearer tratto_live_...'},
)
events = response.json()['data']
for event in events:
print(f"{event['type']} at {event['occurredAt']}")PHP
$tratto = new \Tratto\Client(getenv('TRATTO_API_KEY'));
$events = $tratto->emails->listEvents('email_abc123');
foreach ($events as $event) {
echo "{$event['type']} at {$event['occurredAt']}\n";
}Risposta
{
"data": [
{
"id": "evt_001",
"type": "sent",
"emailId": "email_abc123",
"occurredAt": "2025-06-30T12:00:05Z"
},
{
"id": "evt_002",
"type": "delivered",
"emailId": "email_abc123",
"occurredAt": "2025-06-30T12:00:10Z"
},
{
"id": "evt_003",
"type": "opened",
"emailId": "email_abc123",
"occurredAt": "2025-06-30T12:05:00Z"
},
{
"id": "evt_004",
"type": "clicked",
"emailId": "email_abc123",
"occurredAt": "2025-06-30T12:06:00Z",
"metadata": {
"url": "https://tuodominio.it/offerta?ref=email"
}
}
]
}Polling vs Webhook
Polling (GET /v1/emails/{id})
Quando usare:
- Controlla status su richiesta (utente visualizza dettagli email nel tuo dashboard)
- Scenari a basso volume
- Verifiche di status singole
Vantaggi:
- Semplice da implementare
- Nessuna necessità di infrastruttura webhook
Svantaggi:
- Non real-time (esegui il polling periodicamente)
- Rate-limited
- Latenza più elevata
Esempio:
// Controlla ogni 10 secondi
setInterval(async () => {
const response = await fetch('https://api.tratto.email/v1/emails/email_abc123', {
headers: { 'Authorization': 'Bearer tratto_live_...' },
});
const { data } = await response.json();
if (data.status === 'delivered') {
console.log('Email consegnata!');
clearInterval();
}
}, 10000);Webhook (Push Real-Time)
Quando usare:
- Elaborazione eventi real-time
- Scenari ad alto volume
- Attivare azioni downstream (automazione email, analytics, ecc.)
Vantaggi:
- Real-time
- Nessun overhead di polling
- Efficiente
Svantaggi:
- Richiede endpoint webhook
- Deve verificare le firme HMAC
- Gestire i retry e l'idempotenza
Esempio:
// Il tuo endpoint webhook riceve gli eventi
app.post('/webhooks/tratto', (req, res) => {
const event = req.body;
console.log(`Email ${event.emailId} was ${event.type}`);
if (event.type === 'delivered') {
// Attiva automazione
}
res.status(200).json({ ok: true });
});Vedi Webhook per la configurazione.
Tracciare la Consegna Email
Comprendi i Tipi di Rimbalzo
Hard Bounce: Fallimento permanente della consegna
- Indirizzo email non valido
- Dominio non esiste
- Utente non esiste
Soft Bounce: Fallimento temporaneo della consegna
- Mailbox piena
- Server temporaneamente non disponibile
- Messaggio troppo grande
Complaint: Destinatario ha segnalato come spam (non ri-inviare)
Auto-Unsubscribe
Quando un'email rimbalza o è segnalata, Tratto automaticamente:
- Aggiorna lo status del contatto a
bouncedocomplained - Crea un evento bounce/complaint
- Invia un evento webhook (se configurato)
Puoi quindi:
- Smettere di inviare a indirizzi con rimbalzo
- Implementare campagne di re-engagement per indirizzi segnalati
- Monitorare i tassi di rimbalzo per la salute del dominio
API Riepilogo Status
Ottieni statistiche aggregate su più email.
Coming soon: Endpoint per interrogare gli status email per status, intervallo di date, o tag.
Prossimi Passi
- Configurare webhook real-time? Vedi Webhook
- Inviare email? Vai a Invia Email
- Comprendi la gestione bounce/complaint? Leggi Deliverability
Modifica questa pagina su GitHub
Ultimo aggiornamento