Come inviare email transazionali da Node.js, Python e cURL

Esempi pronti da copiare per inviare email con un’API REST da Node.js, Python, PHP e riga di comando, con timeout, gestione degli errori e un helper riutilizzabile.

Le email transazionali sono i messaggi che il tuo prodotto invia perché un utente ha fatto qualcosa: si è registrato, ha reimpostato la password, ha pagato una fattura, è stato invitato in un workspace. Devono partire rapidamente, dal tuo dominio, e senza rallentare la richiesta che le ha generate.

Questo articolo mostra come inviarle tramite l’API REST di Inbixio dai linguaggi più usati dai team, e poi trasforma la singola chiamata in un piccolo helper da inserire in qualsiasi codebase.

La richiesta, in un unico posto

Tutti gli esempi che seguono inviano la stessa richiesta HTTP:

  • Metodo e URL: POST https://backend.inbixio.com/api/send-email/, compresa la barra finale
  • Autenticazione: un header X-API-Key con una chiave che ha il permesso Send (invio)
  • Corpo: JSON con to_email, subject e message (HTML)

Una chiamata riuscita restituisce 200 con {"message": "Email queued successfully."}. Se non hai ancora creato una chiave o collegato un server SMTP, inizia dalla guida rapida in cinque minuti.

In tutti gli esempi la chiave viene letta da una variabile d’ambiente chiamata INBIXIO_API_KEY. Tienila sul server; non distribuirla mai in un browser o in un’app mobile.

cURL

Utile per testare una chiave, fare debug da un server o chiamare l’API da uno script shell o da un cron job:

curl -sS -X POST https://backend.inbixio.com/api/send-email/ \
  -H "X-API-Key: $INBIXIO_API_KEY" \
  -H "Content-Type: application/json" \
  --max-time 15 \
  -d '{
    "to_email": "ada@example.com",
    "subject": "Your invoice is ready",
    "message": "<p>Hi Ada, your invoice for October is ready.</p>"
  }'

-sS nasconde la barra di avanzamento ma mostra comunque gli errori, e --max-time evita che uno script resti bloccato se la rete si blocca.

Node.js

Node.js 18 e versioni successive includono fetch, quindi non ti serve una libreria HTTP:

// send-email.js
const INBIXIO_URL = 'https://backend.inbixio.com/api/send-email/';

export async function sendEmail({ to, subject, html }) {
  const res = await fetch(INBIXIO_URL, {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.INBIXIO_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ to_email: to, subject, message: html }),
    signal: AbortSignal.timeout(15_000),
  });

  const body = await res.json().catch(() => ({}));
  if (!res.ok) {
    const reason = body.error || body.detail || res.statusText;
    throw new Error(`Inbixio ${res.status}: ${reason}`);
  }
  return body; // { message: 'Email queued successfully.' }
}

Ed ecco come usarlo da una route Express:

app.post('/signup', async (req, res) => {
  const user = await createUser(req.body);
  await sendEmail({
    to: user.email,
    subject: 'Welcome aboard',
    html: `<h1>Welcome, ${escapeHtml(user.name)}!</h1><p>Your account is ready.</p>`,
  });
  res.status(201).json({ id: user.id });
});

Nota escapeHtml. Il campo message viene reso come HTML, quindi tutto ciò che un utente ha digitato, come il suo nome, va sottoposto a escape prima di inserirlo nel corpo.

Python

Con requests:

# send_email.py
import os
import requests

INBIXIO_URL = "https://backend.inbixio.com/api/send-email/"

class EmailError(Exception):
    pass

def send_email(to: str, subject: str, html: str) -> dict:
    res = requests.post(
        INBIXIO_URL,
        headers={"X-API-Key": os.environ["INBIXIO_API_KEY"]},
        json={"to_email": to, "subject": subject, "message": html},
        timeout=15,
    )
    if not res.ok:
        try:
            body = res.json()
        except ValueError:
            body = {}
        reason = body.get("error") or body.get("detail") or res.reason
        raise EmailError(f"Inbixio {res.status_code}: {reason}")
    return res.json()

Passando json= l’header Content-Type viene impostato automaticamente. Imposta sempre un timeout: per impostazione predefinita requests attende all’infinito.

In Django, chiamalo dopo il commit della transazione sul database, così non invierai mai email relative a una riga annullata dal rollback:

from django.db import transaction

transaction.on_commit(lambda: send_email(user.email, "Welcome!", render_welcome(user)))

PHP

<?php
function send_email(string $to, string $subject, string $html): array {
    $ch = curl_init('https://backend.inbixio.com/api/send-email/');
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 15,
        CURLOPT_HTTPHEADER => [
            'X-API-Key: ' . getenv('INBIXIO_API_KEY'),
            'Content-Type: application/json',
        ],
        CURLOPT_POSTFIELDS => json_encode([
            'to_email' => $to,
            'subject'  => $subject,
            'message'  => $html,
        ]),
    ]);
    $body = json_decode(curl_exec($ch), true) ?? [];
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);

    if ($status !== 200) {
        throw new RuntimeException("Inbixio $status: " . ($body['error'] ?? $body['detail'] ?? 'request failed'));
    }
    return $body;
}

Inviare a più persone

Ogni richiesta recapita a un solo to_email. Per avvisare un elenco di utenti, invia una richiesta per destinatario. È comunque ciò che vuoi per le email transazionali: ogni utente riceve il proprio messaggio, nessuno vede l’indirizzo degli altri e un indirizzo non valido non blocca il resto.

Mantieni moderata la concorrenza per non sovraccaricare il tuo server SMTP. Un piccolo pool di 5–10 richieste in parallelo basta per la maggior parte delle app.

Non inviare nel percorso della richiesta

Chiamare l’API è veloce, ma resta pur sempre un round trip di rete. Per tutto ciò che non è urgente, sposta l’invio in un job in background (BullMQ, Celery, Sidekiq, una coda cloud), così:

  • la pagina dell’utente si carica senza attendere l’email,
  • un errore temporaneo può essere ritentato senza che l’utente se ne accorga, e
  • un picco improvviso, come una grande importazione che attiva migliaia di email di benvenuto, viene smaltito a ritmo costante.

Per codici OTP e reimpostazioni della password gli utenti sono in attesa, quindi invia subito e mostra un messaggio di errore chiaro se l’invio non riesce. Gestire errori e limiti dell’API email spiega quali errori ritentare e quali mostrare.

Checklist prima del rilascio

  • La chiave API proviene da una variabile d’ambiente o da un secrets manager, e ha solo il permesso Send.
  • Ogni valore fornito dall’utente nell’HTML è sottoposto a escape.
  • Le richieste hanno un timeout di 10–15 secondi.
  • Le risposte diverse da 200 vengono registrate con il corpo della risposta, così i messaggi in error e detail non vanno persi.
  • Il tuo dominio di invio ha SPF, DKIM e DMARC configurati, così le email arrivano in inbox.

Invialo con Inbixio

Collega il tuo server SMTP, crea una chiave API con permessi mirati e invia da qualsiasi linguaggio con una sola richiesta HTTPS.

Crea un account Vedi i prezzi