Ir al contenido

Vanilla JavaScript (@frontmail/browser)

@frontmail/browser es un SDK diminuto (< 3,5 kB con gzip) y sin dependencias para cualquier sitio web. Su API imita la de @emailjs/browser, así que el código existente necesita pocos cambios.

Ventana de terminal
npm install @frontmail/browser
import { init, send, sendForm, getStatus } from '@frontmail/browser';

Llámalo una vez, antes de enviar:

init({
publicKey: 'pk_4f2a…',
blockHeadless: true, // opcional, consulta Protección contra bots
blockList: { list: ['spam@example.net'], watchVariable: 'email' },
limitRate: { id: 'contact', throttle: 10_000 }, // como máximo un envío cada 10 s
retry: { retries: 3, baseDelayMs: 300 }, // por defecto; `false` desactiva los reintentos
timeoutMs: 15_000, // por intento
apiUrl: 'https://api.frontmail.dev', // por defecto
});

También funciona init('pk_4f2a…') solo con la cadena de la clave.

send(serviceId, templateId, params?, options?)

Sección titulada «send(serviceId, templateId, params?, options?)»
const result = await send('svc_01J9…', 'tpl_order', {
name: 'Jana',
items: [{ title: 'Habitación', qty: 2, price: 89 }],
});
// { messageId: 'msg_…', status: 'queued' | 'held', statusToken: '…', status_code: 202, text: 'OK' }
  • serviceId puede ser null para usar el servicio por defecto de la organización.
  • params se validan en el servidor contra el esquema de la plantilla.
  • options acepta turnstileToken, attachments, idempotencyKey, locale, signal (AbortSignal), publicKey por llamada y protecciones por llamada (blockHeadless, blockList, limitRate). Una cadena simple se trata como la clave pública, igual que en EmailJS.
  • locale (p. ej. 'de') elige un idioma de la plantilla; un idioma desconocido recurre al mismo idioma base y, si no, al idioma predeterminado. result.locale es el idioma en que se envió el correo.

La promesa se resuelve tanto con queued como con held: un mensaje retenido se ha aceptado y se enviará cuando haya créditos disponibles (consulta Cola de correos retenidos). En los demás casos se rechaza con un error tipado (consulta Gestión de errores).

sendForm(serviceId, templateId, form, options?)

Sección titulada «sendForm(serviceId, templateId, form, options?)»
<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>Enviar</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);
// o bien: sendForm('svc_01J9…', 'tpl_contact', '#contact')
});
</script>

El formulario se envía como multipart/form-data. Los campos de texto se convierten en parámetros (convertidos a los tipos declarados), los campos de archivo se convierten en adjuntos y el token de Turnstile de cf-turnstile-response se recoge automáticamente. Usa la site key de tu propio widget de Turnstile: consulta Cloudflare Turnstile.

Los campos que no deben salir de tu sitio se omiten: los campos de contraseña (type="password"), los campos anti-CSRF de los frameworks habituales (csrfmiddlewaretoken, _token, authenticity_token, __RequestVerificationToken, _csrf, csrf_token) y los nombres reservados de la API (accessToken, privateKey, turnstile_key, …). Elige tú los campos con formFields:

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

Para enviar el formulario en un idioma de la plantilla, pasa { locale: 'de' } – se envía como el campo reservado fm_locale – o añade tú mismo un campo fm_locale al formulario (p. ej. un <select name="fm_locale"> de idiomas); el campo del formulario tiene prioridad. Un campo llamado locale sigue siendo un parámetro normal de la plantilla.

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

Con una clave pública solo puedes leer los mensajes que has enviado tú, usando el statusToken del resultado del envío. El SDK lo envía en la cabecera X-Frontmail-Status-Token (no en la URL, para que no acabe en los registros). Consulta Estados de los mensajes.

Fija la versión y usa Subresource Integrity

Sección titulada «Fija la versión y usa Subresource Integrity»

Una etiqueta <script> se ejecuta con acceso completo a tu página. Carga una versión exacta y deja que el navegador verifique su hash, para que un archivo modificado (una CDN o una versión comprometida) se rechace en lugar de ejecutarse:

<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): el hash de cada versión está en sus notas de la versión en GitHub (y en el botón «Copy HTML + SRI» de jsDelivr).
  • CDN de Frontmail: https://cdn.frontmail.dev/v<versión>/frontmail.umd.js; su valor de integrity está en https://cdn.frontmail.dev/v<versión>/sri.json.
  • Para actualizar, cambia la versión y el hash a la vez (consulta el registro de cambios).

Si tu sitio usa CSP, permite:

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