Migrate from EmailJS
Swap one npm package and keep your code. What changes is what an attacker can do with the key you ship to every visitor.
Facts verified 2026-07-17 — corrections: hello@emailfast.dev
One import, same code
Migrating from EmailJS is an npm swap:
- import emailjs from "@emailjs/browser";
+ import emailjs from "@email-fast/browser";
emailjs.init({ publicKey: "ef_pub_..." });
await emailjs.send("default", "template_contact", {
name: "Ada",
message: "Hello from the contact form",
});sendForm works too, with the same signature:
document.querySelector("#contact").addEventListener("submit", (e) => {
e.preventDefault();
emailjs.sendForm("default", "template_contact", e.target);
});Under the hood, the endpoints /api/v1.0/email/send and /api/v1.0/email/send-form accept the EmailJS body — user_id, service_id, template_id, template_params — so even code you can't touch keeps working against a new base URL.
The security upgrade
The reason to switch is not the code you keep; it is the abuse you stop. A key shipped in frontend source is public by definition, so the platform has to assume it is in hostile hands: a browser SDK with EmailJS-compatible endpoints — the recipient always comes from the server-stored template, never from the request, so a public key in your frontend can't be abused to spam arbitrary addresses.
Concretely, per key and template:
- Recipient from the template, always.
template_paramscannot redirect mail. A stolen key sends your contact-form template to your own inbox — that's the ceiling. - Origin allowlist. Each public key lists the origins allowed to use it; requests from anywhere else are refused.
- Typed variable schema. Each template declares what
template_paramsit accepts; unknown keys are stripped and wrong types rejected, so injected content can't smuggle markup into your emails. - Rate caps. Per-key limits bound what a scripted abuser can burn.
- Visitor auto-reply, opted in and capped. If you want the submitter to get a confirmation, you enable it per template with a daily cap.
Try it against the sandbox
Attach the template to a sandbox project first: sandbox keys (ef_sandbox_…) that run the real pipeline dry: real validation, real rendering, real events, a hosted capture inbox — and no email leaves.
Next
Questions, answered plainly
Do I have to rewrite my EmailJS integration?
No. @email-fast/browser keeps the init, send, and sendForm signatures, and the endpoints accept the EmailJS request body — user_id, service_id, template_id, template_params — unchanged.
Can someone abuse the public key in my page source?
They can call it, but the recipient always comes from the server-stored template — never from the request — so the worst they can do is send your own template to you, inside your rate caps and only from allowlisted origins.
Can I still auto-reply to the visitor who submitted the form?
Yes, as an explicit opt-in per template, with a daily cap. It is the one case where a visitor-supplied address receives mail, and it is bounded so it cannot become a spam cannon.