Codici di errore
Ogni risposta di errore ha la stessa forma. docs_url rimanda alla voce corrispondente in questa pagina.
{ "error": { "code": "invalid_template_params", "message": "Invalid template parameters. email: Invalid email address.", "docs_url": "https://docs.frontmail.dev/reference/errors/#invalid-template-params", "details": { "issues": [{ "param": "email", "code": "invalid_email", "message": "Invalid email address." }] } }}Le risposte 429 includono anche l’header Retry-After in secondi. Gli SDK lanciano questi errori
come sottoclassi tipizzate di FrontmailError – vedi Gestione degli errori.
bad_request HTTP 400
Significato: Non è stato possibile interpretare la richiesta (content type errato, JSON illeggibile, metodo non supportato).
Come risolvere: Invia Content-Type: application/json (oppure multipart/form-data per /v1/send-form) e un corpo valido. Gli SDK lo fanno al posto tuo.
invalid_body HTTP 400
Significato: Il corpo JSON è valido ma non corrisponde allo schema, ad esempio manca template_id o un campo ha il tipo sbagliato. details elenca i campi non validi.
Come risolvere: Confronta il corpo con il riferimento della REST API e correggi i campi elencati in details.
invalid_idempotency_key HTTP 400
Significato: L’header Idempotency-Key è vuoto o supera i 255 caratteri.
Come risolvere: Usa un UUID o un’altra stringa univoca di massimo 255 caratteri. Gli SDK ne generano una per ogni invio logico.
unauthorized HTTP 401
Significato: Non è stata fornita alcuna chiave, oppure la chiave non corrisponde a nessuna organizzazione.
Come risolvere: Passa la chiave pubblica come user_id / X-Frontmail-Public-Key, oppure la chiave privata come Authorization: Bearer sk_….
invalid_public_key HTTP 401
Significato: La chiave pubblica non esiste o è stata ruotata.
Come risolvere: Copia la chiave pubblica attuale da Sicurezza → Chiave pubblica nella dashboard. Dopo una rotazione, ripubblica il sito con la nuova chiave.
invalid_private_key HTTP 401
Significato: La chiave privata è sconosciuta o è stata revocata.
Come risolvere: Crea una nuova chiave privata in Sicurezza → Chiavi private e aggiorna il segreto nell’ambiente del tuo server.
insufficient_credits HTTP 402
Significato: La tua organizzazione ha finito i crediti e usa la modalità reject. Nella modalità predefinita hold ricevi invece 202 con status: "held", a meno che la coda dei messaggi in attesa non sia piena (details.reason: "hold_queue_full", con held e limit).
Come risolvere: Acquista un pacchetto di crediti, attiva la ricarica automatica, passa a un piano superiore oppure scegli Metti le email in attesa in Sicurezza → Quando finisci i crediti. Per hold_queue_full, rilascia o scarta anche i messaggi in attesa. Vedi Coda dei messaggi in attesa.
forbidden HTTP 403
Significato: La chiave o l’utente non ha i permessi per questa operazione.
Come risolvere: Controlla il ruolo del membro del team oppure usa una chiave privata per gli endpoint lato server.
origin_not_allowed HTTP 403
Significato: La richiesta proviene da un Origin che non è nell’elenco delle origini consentite, oppure non ha affatto Origin/Referer (server, curl, app nativa) e Consenti app mobile è disattivato. In quel caso details.reason è no_origin.
Come risolvere: Aggiungi il dominio (es. example.com o *.example.com) in Sicurezza → Siti consentiti. Per lo sviluppo in locale serve anche localhost. Per le app native attiva Consenti app mobile; sui server usa una chiave privata invece di quella pubblica.
captcha_required HTTP 403
Significato: Il modello richiede Turnstile e la richiesta non conteneva alcun token.
Come risolvere: Mostra il widget Turnstile (il FrontmailForm di React/Vue/Svelte lo fa per te) oppure passa turnstile_token. Le chiamate lato server con una chiave privata saltano questo controllo.
captcha_failed HTTP 403
Significato: Cloudflare ha rifiutato il token Turnstile: non è valido, è scaduto (i token durano circa 5 minuti) o è già stato usato. Con details.reason: "hostname_mismatch" il widget è stato risolto su un nome host diverso da quello da cui proviene la richiesta.
Come risolvere: Reimposta il widget e fallo risolvere di nuovo all’utente. Non riutilizzare mai un token tra un invio e l’altro. Per hostname_mismatch, aggiungi tutti i nomi host del tuo sito (es. example.com e www.example.com) al tuo widget Turnstile in Cloudflare. Vedi Turnstile.
captcha_not_configured HTTP 403
Significato: Il modello richiede Turnstile, ma la tua organizzazione non ha aggiunto le proprie chiavi Turnstile, quindi le richieste dai siti web non possono essere verificate. In produzione vengono rifiutate anche le chiavi di test di Cloudflare (1x…, superano sempre la verifica) (details.reason: "test_secret").
Come risolvere: Crea un widget Turnstile gratuito nel tuo account Cloudflare e aggiungi la chiave del sito e la chiave segreta in Sicurezza → Protezione dai bot (Turnstile). Oppure disattiva Richiedi CAPTCHA (Turnstile) nel modello. Vedi Turnstile.
headless_blocked HTTP 403
Significato: blockHeadless è attivo e la richiesta sembra provenire da un browser headless.
Come risolvere: È il comportamento previsto per i bot. Se riguarda un utente reale, disattiva blockHeadless nell’init dell’SDK oppure Blocca i browser headless in Sicurezza → Protezione dagli abusi.
recipient_blocked HTTP 403
Significato: Un destinatario o la variabile controllata corrisponde a una voce della tua lista dei bloccati.
Come risolvere: Rimuovi la voce da Sicurezza → Lista dei bloccati se è stata aggiunta per errore.
private_key_required HTTP 403
Significato: L’endpoint (batch, cronologia, modelli) o un’impostazione dell’organizzazione richiede una chiave privata.
Come risolvere: Chiamalo dal tuo server con Authorization: Bearer sk_…: non distribuire mai una chiave privata nel browser.
private_key_in_browser HTTP 403
Significato: Una chiave privata (Authorization: Bearer sk_… o accessToken) è stata inviata con un header Origin, cioè da una pagina web, dove qualsiasi visitatore può leggerla. Le chiavi private sono credenziali lato server.
Come risolvere: Nel browser usa la chiave pubblica e tieni la chiave privata sul tuo server. Se ti serve davvero in un browser (strumento interno), attiva Consenti chiavi private nei browser in Sicurezza, e ruota la chiave se è mai stata pubblica.
email_not_verified HTTP 403
Significato: Il proprietario dell’account non ha ancora verificato il proprio indirizzo email. Gli account non verificati possono consultare la dashboard, ma non inviare.
Come risolvere: Clicca sul link nell’email di verifica oppure inviala di nuovo dal banner nella dashboard.
organization_suspended HTTP 403
Significato: L’organizzazione è stata sospesa, di solito per abusi o per un pagamento contestato.
Come risolvere: Scrivi a support@frontmail.dev dall’indirizzo del proprietario.
plan_limit_reached HTTP 403
Significato: È stato raggiunto un limite del piano diverso dai crediti: numero di modelli, di utenti o una funzionalità non inclusa nel tuo piano. Lo restituiscono anche gli elementi congelati dopo il passaggio a un piano inferiore, sia negli invii sia con Invia di nuovo nella dashboard (details.reason: "template_frozen").
Come risolvere: Passa a un piano superiore (modelli e membri congelati vengono scongelati automaticamente) oppure elimina dei modelli / revoca gli inviti in sospeso per fare spazio. Vedi Piani e Cambi di piano.
dynamic_recipient_not_allowed HTTP 403
Significato: Un campo destinatario (A/CC/CCN) è composto da un parametro, ma il modello non consente destinatari dinamici. Questo ti protegge dall’essere usato come open relay.
Come risolvere: Attiva Consenti destinatario dinamico nelle impostazioni del modello (Impostazioni → Protezione) solo se ti serve davvero e hai attivato Turnstile e le origini consentite.
dynamic_recipient_requires_captcha HTTP 403
Significato: Il modello prende il destinatario dai parametri e la richiesta usa la chiave pubblica, ma il modello non richiede il CAPTCHA. Senza di esso, chiunque copi la tua chiave pubblica potrebbe inviare il tuo modello a qualsiasi indirizzo.
Come risolvere: Aggiungi le tue chiavi Cloudflare Turnstile in Sicurezza → Protezione dai bot e attiva Richiedi CAPTCHA per il modello, oppure invia questo modello dal tuo server con una chiave privata. Vedi Domini consentiti per i link e blocco dei contenuti.
dynamic_field_not_allowed HTTP 403
Significato: Un campo del mittente è composto da parametri e la richiesta usa la chiave pubblica: l’indirizzo del mittente non può mai esserlo, e nei modelli con destinatario dinamico non possono esserlo nemmeno il nome del mittente e il Reply-To. details.fields li elenca.
Come risolvere: Usa valori fissi nel modello (l’indirizzo del visitatore va nel Reply-To solo quando il destinatario è fisso, ad es. in un modulo di contatto), oppure invia dal tuo server con una chiave privata.
link_not_allowed HTTP 403
Significato: L’email generata contiene un link a un dominio fuori dai tuoi domini consentiti per i link. Il controllo vale per gli invii con chiave pubblica a modelli con destinatario dinamico, per le risposte automatiche e per i modelli con Consenti solo link a domini consentiti. details.hosts elenca i domini non consentiti (mai l’URL completo).
Come risolvere: Aggiungi il dominio in Sicurezza → Domini consentiti per i link, scrivi il link direttamente nel modello oppure toglilo dai parametri. Vedi Domini consentiti per i link e blocco dei contenuti.
attachments_not_allowed HTTP 403
Significato: La richiesta contiene allegati dinamici, ma il modello non li consente, il tuo piano non include allegati (Free) oppure il tipo di file è bloccato (eseguibili, script, immagini disco, HTML/SVG, file Office con macro). Anche POST /v1/uploads con la chiave pubblica richiede almeno un modello che consenta gli allegati.
Come risolvere: Attiva Consenti allegati dal modulo nelle impostazioni del modello e verifica che il tuo piano includa gli allegati.
not_found HTTP 404
Significato: L’URL non corrisponde a nessun endpoint.
Come risolvere: Controlla il percorso e il prefisso /v1.
service_not_found HTTP 404
Significato: Il service_id non esiste nell’organizzazione di questa chiave, oppure non è impostato un servizio predefinito.
Come risolvere: Copia l’ID da Servizi email oppure imposta un servizio come predefinito.
template_not_found HTTP 404
Significato: Il template_id non esiste nell’organizzazione di questa chiave.
Come risolvere: Copia l’ID modello da Modelli. Le chiavi di un’altra organizzazione non vedono il modello.
message_not_found HTTP 404
Significato: Il messaggio non esiste, è più vecchio del periodo di conservazione della cronologia oppure lo status token non corrisponde.
Come risolvere: Usa il message_id e lo status_token della risposta all’invio.
conflict HTTP 409
Significato: La risorsa è stata modificata in contemporanea o si trova in uno stato che non consente l’operazione (ad es. rilasciare un messaggio già inviato). Con details.reason: "subscription_not_active" un cambio di piano è stato rifiutato perché l’abbonamento ha una fattura non pagata.
Come risolvere: Ricarica la risorsa e riprova. Per subscription_not_active, paga la fattura aperta (Fatturazione → Piano → Gestisci carte e fatture) e poi cambia piano.
idempotency_conflict HTTP 409
Significato: La stessa Idempotency-Key è stata usata nelle ultime 24 ore con un corpo della richiesta diverso.
Come risolvere: Genera una nuova chiave per ogni nuovo invio logico. Riusa una chiave solo quando ritenti la stessa identica richiesta.
payload_too_large HTTP 413
Significato: Il corpo della richiesta supera il limite di dimensione.
Come risolvere: Sposta i file grandi negli upload e mantieni i parametri leggeri.
attachment_too_large HTTP 413
Significato: La dimensione totale degli allegati in una richiesta supera il limite del tuo piano.
Come risolvere: Comprimi i file, invia un link al loro posto oppure passa a un piano superiore. Vedi Piani.
invalid_template_params HTTP 422
Significato: I parametri non corrispondono allo schema del modello: manca un parametro obbligatorio, un valore ha il tipo sbagliato o viola una regola (lunghezza, intervallo, pattern, enum). In modalità rigorosa falliscono anche i parametri sconosciuti. Gli invii con chiave pubblica a modelli con destinatario dinamico rifiutano inoltre i parametri HTML e i valori oltre i 500 caratteri (details.reason: "content_locked"). details contiene una voce per ogni campo.
Come risolvere: Correggi i campi elencati in details. Genera i tipi con npx frontmail types per individuare il problema già in fase di compilazione.
translation_not_configured HTTP 422
Significato: È stata richiesta una traduzione automatica, ma l’organizzazione non ha una chiave API di un provider di traduzione (o non di quello richiesto).
Come risolvere: Aggiungi la tua chiave OpenAI, Anthropic, Gemini o DeepL in Impostazioni → Traduzione automatica. Vedi Traduzioni dei modelli.
translation_invalid HTTP 422
Significato: Il provider ha restituito una traduzione che modifica la struttura del modello: manca o è diversa un’espressione Handlebars, un link o l’indirizzo di un’immagine. Non è stato salvato nulla.
Come risolvere: Riprova, prova un altro provider o modello, oppure traduci la variante a mano.
translation_provider_auth HTTP 422
Significato: Il provider di traduzione ha rifiutato la chiave API dell’organizzazione (non valida, scaduta o senza accesso al modello).
Come risolvere: Sostituisci la chiave in Impostazioni → Traduzione automatica o scegli un modello a cui il tuo account ha accesso.
template_render_failed HTTP 422
Significato: Handlebars non è riuscito a generare il modello con questi parametri (ad es. #each su qualcosa che non è un elenco, un helper sconosciuto).
Come risolvere: Apri l’editor del modello: il pannello dei controlli mostra il problema. Prova con gli stessi parametri nell’anteprima.
invalid_recipient HTTP 422
Significato: Dopo la generazione, un valore di A/CC/CCN/Reply-To non è un indirizzo email valido, oppure A è vuoto.
Come risolvere: Controlla i campi destinatario del modello e i parametri che usano.
sender_not_configured HTTP 422
Significato: L’email non ha un indirizzo mittente: il modello non ne ha uno e il servizio email non ha un mittente predefinito (né un account collegato o un nome utente SMTP in formato email da usare in alternativa). Viene restituito dagli invii di prova dalla dashboard.
Come risolvere: Imposta Email mittente predefinita nelle impostazioni del servizio (Servizi email → servizio) oppure un’email mittente nelle impostazioni del modello. Con Amazon SES e la maggior parte delle API l’indirizzo deve essere un’identità verificata.
rate_limited HTTP 429
Significato: Troppe richieste rispetto al tuo piano, IP, chiave o all’impostazione limitRate, oppure il rilevamento delle anomalie ha rallentato la tua organizzazione. details.scope: "recipient" significa che il destinatario ha già ricevuto il numero massimo giornaliero di email con destinatario dinamico (Sicurezza → Email per destinatario al giorno); details.scope: "uploadbytes" significa che il volume giornaliero di upload con chiave pubblica è esaurito.
Come risolvere: Attendi Retry-After secondi (gli SDK lo fanno automaticamente). Per gli invii massivi usa /v1/send-batch. Vedi Rate limit.
test_send_limit HTTP 429
Significato: Hai esaurito gli invii di prova gratuiti di oggi dall’editor dei modelli (20 al giorno).
Come risolvere: Aspetta fino a domani (UTC) oppure invia un messaggio reale tramite l’API.
recipient_suppressed HTTP 451
Significato: Il destinatario è nella tua lista di soppressione dopo un mancato recapito permanente, una segnalazione di spam o un inserimento manuale. Non viene consumato alcun credito.
Come risolvere: Rimuovi l’indirizzo dalla Lista di soppressione solo se sei sicuro che sia valido e che la persona voglia ricevere le tue email.
internal_error HTTP 500
Significato: Qualcosa non ha funzionato da parte nostra.
Come risolvere: Riprova con la stessa Idempotency-Key (sicuro, nessun duplicato). Se il problema persiste, controlla status.frontmail.dev e contatta l’assistenza indicando l’ID della richiesta.
provider_error HTTP 502
Significato: Il provider email ha restituito un errore imprevisto durante un’operazione sincrona, ad esempio il test di un servizio.
Come risolvere: Apri il servizio nella dashboard per vedere il messaggio del provider. Vedi le guide ai provider.
translation_provider_error HTTP 502
Significato: Il provider di traduzione non ha risposto o ha restituito un errore. details.status contiene lo stato HTTP.
Come risolvere: Riprova più tardi. La causa più comune sono i limiti o la quota del tuo account presso il provider.
Errori lato client (SDK)
Questi codici vengono generati dagli SDK senza una risposta dell’API. L’errore ha stato 0.
network_error SDK
Significato: La richiesta non ha mai ricevuto una risposta HTTP: dispositivo offline, errore DNS, blocco da parte di un’estensione o di una regola CORS/CSP. L’SDK ha già ritentato con backoff.
Come risolvere: Controlla la connessione e la tua Content-Security-Policy (connect-src https://api.frontmail.dev). Chiedi all’utente di riprovare.
timeout SDK
Significato: Un tentativo ha superato timeoutMs (predefinito 15 s) e anche tutti i nuovi tentativi sono andati in timeout.
Come risolvere: Riprovare è sicuro: l’SDK riusa la chiave di idempotenza, quindi non viene inviato alcun duplicato.
aborted SDK
Significato: L’AbortSignal passato in options.signal è stato interrotto.
Come risolvere: Non c’è niente da correggere: di solito il componente è stato smontato o l’utente ha cambiato pagina.
invalid_response SDK
Significato: Il server ha risposto con qualcosa che non è una risposta JSON di Frontmail: tipicamente un proxy, un captive portal o un apiUrl sbagliato.
Come risolvere: Controlla l’opzione apiUrl ed eventuali proxy tra il client e api.frontmail.dev.
not_initialized SDK
Significato: send() è stato chiamato prima di init() e senza una chiave nelle opzioni della chiamata.
Come risolvere: Chiama init({ publicKey }) una volta all’avvio, oppure passa la chiave come ultimo argomento.
private_key_in_browser SDK
Significato: Una chiave privata (privateKey, o accessToken in @frontmail/emailjs-compat) è stata configurata in codice eseguito in un browser web, oppure @frontmail/node è stato incluso nel bundle di una pagina. Chiunque visiti la pagina potrebbe copiare la chiave e leggere la cronologia dei tuoi messaggi.
Come risolvere: Nel browser usa la chiave pubblica (pk_…) e tieni la chiave privata sul tuo server. Se la chiave privata è mai finita su una pagina, ruotala. Solo per uno strumento interno su computer fidati, passa dangerouslyAllowPrivateKeyInBrowser: true.