Home/Email API/EmailJS vs a backend

EmailJS, and why client-side sending isn't enough

EmailJS exists for one honest reason: sending email from a contact form without writing a backend. Here's where that holds up, and where it doesn't.

Verified By Kam Low, Co-founder · Updated

The job EmailJS does

A static site needs a contact form; a contact form needs to send email; email needs a server you don't have. EmailJS bridges that: your front-end calls their API with a public key, their servers send through your connected mail account. For a portfolio site's contact form, that's the whole job, done.

Where client-side sending stops

Everything in the browser is public: your template IDs, your public key, your rate limits, all inspectable and scriptable by anyone who opens devtools. There's no way to send transactional email safely (a password reset triggered purely client-side is an attacker's toy), no delivery events you can trust, and the free tier caps fast.

The pattern that scales keeps the form client-side and moves the send server-side: the form captures the contact against a public endpoint, and the email fires from the platform, where secrets live and events flow.

We built that public endpoint the paranoid way, and it shows what client-side surfaces demand: it always returns the same success response whether or not the contact exists, so nobody can use your form to enumerate email addresses, and it's idempotent, so double-submits change nothing. That is the level of thinking your contact form needs, and it's exactly what a client-side sending key can never give you.

The paranoia is earned. In June a bot wave signing up from one disposable domain pushed about 6,400 phishing sends through roughly 40 throwaway accounts before we closed the gap. The fix added a disposable and blocked email-domain trigger to the signup gate, with full-domain and dot-boundary subdomain matching against a curated blocklist, and IP capture on every account-creation path including OAuth. Public-facing forms attract exactly this traffic, which is why ours fail closed.

We ship a browser-safe public client for exactly this pattern, @nitrosend/sdk/browser, so the front-end capture is typed and clean while every send stays server-side. And the loop it feeds is real: a full onboarding flow can be designed and switched on from a single Claude prompt. Form captures, flow nurtures, nothing sent from the browser.

The mechanics under that are worth spelling out. The signup attaches the contact to a chosen list, and the list membership itself fires the welcome flow. No server of your own, no secret key exposed anywhere, and the same outcome the client-side sending approach was reaching for.

The key design enforces the boundary mechanically. Server code holds a secret key. The browser package takes only a public website key, requires an origins allowlist so another site can't lift the key and reuse it, and is hardcoded to refuse a secret key outright if someone tries to initialize it with one. The safe pattern shouldn't depend on developers reading the docs. It should be the only pattern that runs.

Full parameters and responses live in the REST API docs and the API reference.

The trap
Gmail app password
abcd efgh ijkl mnop
✕ 500 emails/day cap
✕ breaks when 2FA settings change
✕ a full-inbox credential in your code
The fix
POST /v1/messages
Authorization: Bearer ns_live_…
✓ scoped API key, revoke anytime
✓ 8,000 free sends, no daily cliff
✓ delivery events you can act on

Go deeper

Zoom out from EmailJS entirely for a second. The honest fix for a contact form that needs to send mail is not a better client-side key or a tighter server boundary, it is not hand-wiring the send at all. Describe the flow to Claude, Cursor, or Codex and our MCP server builds and sends it on the same account, with the same guardrails I described above, no widget snippet to embed.

The server-side send is one call from Node.js or TypeScript, and serverless functions mean "a backend" is ten lines on Vercel or Cloudflare. A server-side API key unlocks the full account surface, and it belongs in that function's environment, never in the bundle. OAuth is the other route worth knowing about, since most of our clients support signing in through the browser without an API key at all. The server-side fix is the same one every sender ends up at: SPF, DKIM and DMARC authentication, backed by how to set up SMTP so the domain is provably yours.

FAQ

What is EmailJS?

A service that sends email directly from client-side JavaScript through a public key, built for contact forms on sites without a backend. Fine for that job; unsafe and untrackable for anything a product depends on.

Why shouldn't I send transactional email from the browser?

Anything client-side is user-controllable: an attacker can fire your sends, exhaust your quota, or spoof your templates. Transactional email needs a server-held secret and delivery events, which means an API call from your backend or a serverless function.

First send in thirty seconds.

Simple pricing. Unlimited contacts.

Every plan includes full stack emailing: Flows, Newsletter Campaigns and Transactional Email, plus our NitroWheel LLM and all agent integrations (Claude, ChatGPT, Codex, Cursor and others). Pay for what you send, not who you store.

Daily allowances depend on your plan and sender standing. Strong list, domain and delivery evidence can raise standing, including on day one. Trusted receives the full plan allowance; available email credits, safety checks and delivery pacing still apply.

Free
$0
forever
  • Emails 8,000then 500/mo
  • Email types Transactional & Marketing
  • AI actions 20/mo
  • Contacts Free & Unlimited
  • Brands 3
  • Seats 1
  • Recipients / rolling 24h 100–5,000
  • Email validation Prepaid only
Start free
Ultra
$100
per month
  • Emails 125,000/month
  • AI actions 5,000/mo
  • Brands 10
  • Seats 10 · Domains 10
  • Frontier AI Included
  • Dedicated IP Available
  • Recipients / rolling 24h 1,000–625,000
  • Email validation Prepaid only
Get started
Enterprise
$300
per month
  • AI actions Unlimited
  • Unlimited brands & domains Included
  • SSO / SAML Included
  • 99.9% SLA Included
  • Recipients / rolling 24h Contracted
  • Email validation Prepaid only
Get started

Free forever. No credit card required. See full comparison →