Email

Invio email transazionale.

POST/api/v1/emailsInvia un'email transazionale. `idempotencyKey` nel body obbligatoria (min 8 char); `from`/`replyTo` accettano 'Nome <[email protected]>'.(scope: email:send)
GET/api/v1/emails/:idStato di un invio (metadati + timeline eventi).
POST/api/v1/messagesInvio transazionale unificato email/WhatsApp/Telegram.(scope: messages:send)

POST /api/v1/emails

Parametri del body (JSON):

CampoTipoObblig.Note
tostring o arrayUno o più destinatari: [email protected], Nome <[email protected]>, più indirizzi separati da virgola nella stessa stringa, oppure un array.
fromstring[email protected] oppure Nome <[email protected]>. Il dominio deve essere verificato.
subjectstringsì*Min 1 char. Opzionale se il template fornisce il subject.
htmlstringsì*HTML del messaggio. In alternativa usa templateId.
textstringnoVersione testo semplice (parte multipart).
replyTostringnoReply-To: [email protected] o Nome <[email protected]>.
ccstring o arraynoCopie visibili: compaiono nell'header Cc. Stesse forme di to.
bccstring o arraynoCopie nascoste: non compaiono in nessun header del messaggio. Stesse forme di to.
templateIdstringnoId (uuid) o nome del template del tenant; alternativo a html.
variablesobjectnoVariabili di interpolazione del template.
attachmentsarraynoAllegati: { id }, { filename, content } (base64) o { filename, url }. Vedi Allegati.
idempotencyKeystringMin 8 caratteri. Previene i doppi invii sui retry. Va nel body, non in un header.
disableTrackingbooleannoDisattiva pixel/redirect per questo invio (default false).
disableUtmbooleannoSalta l'auto-tagging UTM dei link (default false).
* subject/html sono richiesti se non usi un templateId che li fornisce.

Massimo 50 destinatari per messaggio (to + cc + bcc), limite di SES: oltre, la risposta è 422 too_many_recipients. Ogni destinatario consuma una unità della quota mensile del piano. Le copie in suppression (bounce, complaint, unsubscribe) vengono tolte dall'invio e riportate nella risposta in droppedRecipients; la richiesta è un 409 solo quando non resta nemmeno un destinatario to a cui inviare. Aperture e click sono per messaggio, non per destinatario: non distinguono chi delle copie ha aperto.

Ogni campo indirizzo accetta sia [email protected] sia Nome <[email protected]>, e to, cc e bcc prendono anche più indirizzi insieme, come array o separati da virgola dentro una sola stringa ("[email protected], [email protected]"). Una virgola dentro un display name fra virgolette non separa niente: "Neri, Sara" <[email protected]> è un destinatario solo. Più to finiscono nell'header To, non in Cc, e GET /api/v1/emails/{id} li restituisce in toAddresses.

Risposte: 202 ({ id, status: "queued" }), 200 ({ status: "duplicate", idempotencyKey, id }), 422 (validazione), 402 (quota piano), 403 (domain_not_verified), 409 (suppressed).

Esempio

import { Sending } from "sending-sdk";
 
const sending = new Sending({ apiKey: process.env.SENDING_API_KEY! });
 
const { id } = await sending.emails.send({
  from: "Acme <[email protected]>",
  to: "[email protected]",
  subject: "Ciao",
  html: "<p>Hey</p>",
  replyTo: "Supporto <[email protected]>",
  idempotencyKey: "ciao-sara-001",
});

POST /api/v1/emails/batch

Fino a 100 email in una richiesta. Il body è { "emails": [...] } e ogni elemento è esattamente il body di POST /api/v1/emails, idempotencyKey compresa.

L'esito è parziale, non tutto o niente: la risposta è 207 e results è allineato per indice all'array inviato, quindi un indirizzo invalido su 60 non impedisce gli altri 59.

Campo del risultatoNote
indexPosizione nell'array emails inviato.
statusaccepted oppure failed.
idId del messaggio, presente sugli accettati (duplicati compresi).
duplicatetrue se quella idempotencyKey era già stata accettata: non è un errore.
droppedRecipientsCopie escluse perché in suppression.
error{ code, message } sui falliti: validation_error, domain_not_verified, suppressed, template_not_found, quota_exceeded, too_many_recipients.

L'idempotenza vale per elemento: un batch ritentato non produce doppi invii, e gli elementi già accettati tornano accepted con duplicate: true. Ai fini dei limiti di frequenza la chiamata conta una richiesta.

const esito = await sending.emails.sendBatch([
  { from: "Acme <[email protected]>", to: "[email protected]", subject: "Ciao", html: "<p>hey</p>", idempotencyKey: "b-001" },
  { from: "Acme <[email protected]>", to: "[email protected]", subject: "Ciao", html: "<p>hey</p>", idempotencyKey: "b-002" },
]);
for (const r of esito.results) {
  if (r.status === "failed") console.error(`elemento ${r.index}: ${r.error?.code}`);
}

Risposta:

{
  "accepted": 2,
  "failed": 1,
  "results": [
    { "index": 0, "status": "accepted", "id": "8f1c…" },
    { "index": 1, "status": "accepted", "id": "0b22…", "duplicate": true },
    { "index": 2, "status": "failed", "error": { "code": "suppressed", "message": "complaint" } }
  ]
}

GET /api/v1/emails/:id

Stato di un invio: usa l'id restituito dall'invio.

const status = await sending.emails.get(id);
console.log(status.status, status.events);

Ritorna status, metadati (to, from, subject, provider, createdAt), gli attachments dell'invio (id, filename, contentType, size) e la timeline events (sent, delivered, open, click, bounce, complaint).

Schema completo e "try it" nella API reference interattiva (OpenAPI).