Salta ai contenuti

Vanilla JavaScript (@frontmail/browser)

@frontmail/browser è un SDK minuscolo (< 3,5 kB con gzip) e senza dipendenze, per qualsiasi sito web. La sua API ricalca quella di @emailjs/browser, quindi il codice esistente richiede poche modifiche.

Finestra del terminale
npm install @frontmail/browser
import { init, send, sendForm, getStatus } from '@frontmail/browser';

Chiamala una volta, prima di inviare:

init({
publicKey: 'pk_4f2a…',
blockHeadless: true, // facoltativo, vedi Protezione dai bot
blockList: { list: ['spam@example.net'], watchVariable: 'email' },
limitRate: { id: 'contact', throttle: 10_000 }, // al massimo un invio ogni 10 s
retry: { retries: 3, baseDelayMs: 300 }, // predefinito; `false` disattiva i tentativi
timeoutMs: 15_000, // per tentativo
apiUrl: 'https://api.frontmail.dev', // predefinito
});

Funziona anche init('pk_4f2a…') con la sola stringa della chiave.

const result = await send('svc_01J9…', 'tpl_order', {
name: 'Giulia',
items: [{ title: 'Camera', qty: 2, price: 89 }],
});
// { messageId: 'msg_…', status: 'queued' | 'held', statusToken: '…', status_code: 202, text: 'OK' }
  • serviceId può essere null per usare il servizio predefinito dell’organizzazione.
  • I params vengono validati sul server rispetto allo schema del modello.
  • options accetta turnstileToken, attachments, idempotencyKey, locale, signal (AbortSignal), publicKey per la singola chiamata e i controlli per la singola chiamata (blockHeadless, blockList, limitRate). Una semplice stringa viene trattata come chiave pubblica, come in EmailJS.
  • locale (ad es. 'de') sceglie una lingua del modello; una lingua sconosciuta ripiega sulla stessa lingua di base, poi sulla lingua predefinita. result.locale è la lingua in cui è stata inviata l’email.

La promise viene risolta sia per queued sia per held – un messaggio in attesa è accettato e verrà inviato non appena ci saranno crediti disponibili (vedi Coda dei messaggi in attesa). Negli altri casi viene rifiutata con un errore tipizzato (vedi Gestione degli errori).

<form id="contact">
<input name="name" required>
<input name="email" type="email" required>
<textarea name="message"></textarea>
<input type="file" name="attachment">
<div class="cf-turnstile" data-sitekey="YOUR_TURNSTILE_SITE_KEY"></div>
<button>Invia</button>
</form>
<script type="module">
import { init, sendForm } from '@frontmail/browser';
init({ publicKey: 'pk_4f2a…' });
document.getElementById('contact').addEventListener('submit', async (event) => {
event.preventDefault();
const { status } = await sendForm('svc_01J9…', 'tpl_contact', event.target);
// oppure: sendForm('svc_01J9…', 'tpl_contact', '#contact')
});
</script>

Il modulo viene inviato come multipart/form-data. I campi di testo diventano parametri (convertiti nei tipi dichiarati), i campi file diventano allegati e un token Turnstile in cf-turnstile-response viene raccolto automaticamente. Usa la chiave del sito del tuo widget Turnstile – vedi Cloudflare Turnstile.

I campi che non devono lasciare il tuo sito vengono saltati: i campi password (type="password"), i campi anti-CSRF dei framework più comuni (csrfmiddlewaretoken, _token, authenticity_token, __RequestVerificationToken, _csrf, csrf_token) e i nomi riservati dell’API (accessToken, privateKey, turnstile_key, …). Puoi scegliere tu i campi con formFields:

await sendForm('svc_01J9…', 'tpl_contact', '#contact', {
formFields: { include: ['name', 'email', 'message'] }, // solo questi (+ token Turnstile)
// oppure: formFields: { exclude: ['internal_note'] }
});

Per inviare il modulo in una lingua del modello, passa { locale: 'de' } – viene inviato come campo riservato fm_locale – oppure aggiungi tu stesso un campo fm_locale al modulo (ad es. un <select name="fm_locale"> per la lingua); il campo del modulo ha la precedenza. Un campo chiamato locale resta un normale parametro del modello.

const status = await getStatus(result.messageId, { token: result.statusToken });
// { messageId, status: 'sent', createdAt, sentAt, templateId, serviceId, events: [...] }

Con una chiave pubblica puoi leggere solo i messaggi che hai inviato tu, usando lo statusToken del risultato dell’invio. L’SDK lo invia nell’header X-Frontmail-Status-Token (non nell’URL, così non finisce nei log). Vedi Stati dei messaggi.

Un tag <script> ha pieno accesso alla tua pagina. Carica una versione esatta e lascia che il browser ne verifichi l’hash, così un file modificato (una CDN o una release compromessa) viene rifiutato invece che eseguito:

<script
src="https://cdn.jsdelivr.net/npm/@frontmail/browser@0.1.0/dist/frontmail.umd.js"
integrity="sha384-g2Rxznkz2yb/YYSdVTkXLxZFZ2Nh2+XdhPStxh0stydXFF3gYjDuyHimWIZLJDCc"
crossorigin="anonymous"></script>
  • jsDelivr (npm): l’hash di ogni release si trova nelle note di rilascio su GitHub (e nel pulsante «Copy HTML + SRI» di jsDelivr).
  • CDN di Frontmail: https://cdn.frontmail.dev/v<versione>/frontmail.umd.js; il valore di integrity si trova in https://cdn.frontmail.dev/v<versione>/sri.json.
  • Per aggiornare, cambia la versione e l’hash insieme (vedi il changelog).

Se il tuo sito usa una CSP, consenti:

connect-src https://api.frontmail.dev;
script-src https://cdn.jsdelivr.net https://challenges.cloudflare.com; # build CDN (o cdn.frontmail.dev), Turnstile
frame-src https://challenges.cloudflare.com; # Turnstile