Skip to content

EmailJS compatibility (@frontmail/emailjs-compat)

@frontmail/emailjs-compat exposes the same functions and signatures as @emailjs/browser, but talks to Frontmail. Existing code keeps working after you change the import and the IDs.

Terminal window
npm uninstall @emailjs/browser
npm install @frontmail/emailjs-compat
import emailjs from '@emailjs/browser';
import emailjs from '@frontmail/emailjs-compat';
emailjs.init({ publicKey: 'pk_4f2a…' });
emailjs.send('svc_01J9…', 'tpl_01J9…', { name: 'Jana' });
emailjs.sendForm('svc_01J9…', 'tpl_01J9…', '#contact-form');
  • init(publicKey) and init({ publicKey, blockHeadless, blockList, limitRate, storageProvider }), with an optional second argument for the API origin (default https://api.frontmail.dev).
  • send(serviceID, templateID, templateParams?, options?) and sendForm(serviceID, templateID, form, options?), with options as a public key string or an options object.
  • The resolved value is an EmailJSResponseStatus with status (200) and text ('OK'), like EmailJS, plus Frontmail extras: messageId, deliveryStatus ('queued' or 'held') and statusToken.
  • Errors are thrown as EmailJSResponseStatus objects with status and text, so existing catch handlers work. The underlying FrontmailError (with code and docsUrl) is in error.error.
  • The REST paths /api/v1.0/email/send and /api/v1.0/email/send-form exist on api.frontmail.dev, with the EmailJS body fields service_id, template_id, user_id, template_params, accessToken.
  • The IDs and keys are Frontmail’s: svc_…, tpl_…, pk_…, sk_….
  • Templates use Frontmail syntax (Handlebars) and typed params. Most {{variable}} templates work unchanged; see the migration guide.
  • Frontmail may resolve with a held message when you are out of credits (still a success). The compat layer reports it as status: 200 with deliveryStatus: 'held'; @frontmail/browser returns status: 'held' directly.
  • Frontmail retries network errors and 5xx automatically with an idempotency key.
  • accessToken (a private key) is refused in the browser: send / sendForm reject with status: 400 and error.code === 'private_key_in_browser'. Remove it from front-end code – see the migration guide. Server-side code (Node.js, no document) may still pass it.
  • sendForm skips password inputs, anti-CSRF fields of common frameworks and reserved names such as accessToken (see sendForm).
  • blockHeadless, blockList and limitRate run in the browser and are a convenience, not a security control – enforce limits in Security in the dashboard.

When you’re ready, switching to @frontmail/browser or a framework SDK is straightforward and gives you typed results, typed params and getStatus.