# Send from the browser without an abusable secret

> Send email from your frontend with a browser SDK that can't be abused: the recipient always comes from a server-stored template, never the request.

Canonical: https://emailfast.dev/features/frontend

## The contact-form problem, solved structurally

You can send email from frontend code with `@email-fast/browser` and no backend at
all. The key you ship in the page is public by design and safe by structure:
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. Rate limiting is on top of the safety story here, not the whole of
it.

## How it works

1. Create a template server-side. Its recipient — you, your support inbox — is fixed there. Nothing in a browser request can choose or change it.
2. Give the template a typed `variable_schema` (`string`, `email`, `number`, `boolean`, with `required`, `maxLen`, `enum`). Requests with unknown, missing, or oversized fields are rejected.
3. Allowlist your origins for the key and set per-key rate caps.
4. Optionally enable a visitor auto-reply — "we got your message" — capped per visitor per day.

## The evidence

:::panel The whole request, EmailJS-shaped
```json
// POST /api/v1.0/email/send
{
  "user_id": "your_public_key",
  "service_id": "default",
  "template_id": "contact_form",
  "template_params": { "name": "Ada", "message": "Hello there" }
}
```
Notice what's missing: a `to` field. There isn't one, and there is nothing to
substitute for it — the recipient lives in the template, on the server.
`template_params` is validated against the template's typed schema before admission.
:::

## Honest limits

:::tradeoffs A deliberately narrow lane
This lane is for contact forms, feedback, and lead capture — mail that comes to you.
Arbitrary recipients require the [REST API](/features/email-api) and a server, on
purpose. Origin allowlists stop browsers, not `curl` — any non-browser client can
forge an `Origin` header — which is exactly why recipient pinning and per-key caps
exist: the allowlist cuts noise, the structure prevents harm. And rate caps bind
honest traffic spikes too; raise them deliberately, not reactively.
:::

## Where to go next

Five-minute setup in the [browser quickstart](/docs/quickstart-browser). Collecting
subscribers rather than messages? That's [signup forms](/features/forms). The
[developer door](/developers) covers the rest of the surface, and the
[comparison](/compare/emailjs-alternative) is the honest read if you're deciding
whether to switch.

## Can someone take my public key and spam people?

No. The recipient is pinned in the server-stored template; no field in any request can select an address. A stolen key can only send your own templates to you, within your rate caps and origin allowlist.

## Is it compatible with existing EmailJS code?

Yes — the endpoint ( /api/v1.0/email/send ) and body shape ( user_id , service_id , template_id , template_params ) match, so migrating is changing the endpoint and the key, not the code. See the migration comparison .

## What stops junk data in template variables?

Each template declares a typed variable_schema — string , email , number , boolean , with required , maxLen , and enum constraints. Requests with unknown, missing, or oversized fields are rejected before admission.

## Can I send visitors an automatic confirmation?

Yes — an optional visitor auto-reply, capped per visitor per day, so a reply loop or a malicious script can't turn your form into a mail cannon.
