Pick your language, paste your API key, send your first email.
Every request to /v1/* must carry an API key.
Keys are scoped to a workspace + application pair and never expire unless revoked.
js2_live_<prefix:8>_<secret:32>
Prefix is stored plain (fast lookup). Secret is stored as SHA-256 — we can't recover it after creation. Copy it when generated; rotate via Dashboard → API Keys if lost.
X-Api-Key: js2_live_... # or equivalently: Authorization: Bearer js2_live_...
Both headers are accepted. X-Api-Key is preferred for clarity.
Base URL: https://js2mail.dev
No official SDK package yet — the API is a single POST. These copy-paste snippets are all you need.
Every delivery carries an HMAC-SHA256 signature so you can confirm the request came from JS2Mail and wasn't tampered with in transit.
X-JS2Mail-Signature: t=1748000000,v1=abc123...
t = Unix timestamp of delivery.
v1 = HMAC-SHA256 hex of t + "." + body using the webhook secret.
Reject deliveries where t is more than 5 minutes old — this prevents replay attacks using captured valid signatures.
Each delivery also carries a stable X-JS2Mail-Delivery-Id UUID — store it and deduplicate on your side for idempotent processing.
Pass "idempotencyKey": "your-key" in the request body.
If a request with the same key has already been accepted for your Application, the API returns the original response — no second mail goes out.
The key is scoped to (workspace, application) — the same key value is independent across different applications.
// ✅ domain-specific, naturally unique "order-confirmation-order_789" "password-reset-user_42-2026-06-01" // ✅ UUID generated before the HTTP call "3f2504e0-4f89-11d3-9a0c-0305e82c3301" // ❌ too generic — collides across users "welcome-email"
When you receive a 429, wait before retrying.
Recommended strategy: start at 1s, double on each attempt, cap at 60s, jitter ±20%.
delay = min(1 * 2^attempt, 60) * (0.8 + random() * 0.4)
JS2Mail retries failed sends automatically — up to 6 attempts with exponential backoff (1m → 5m → 25m → 2h → 10h → 24h).
Permanent provider errors (4xx) skip the retry queue. A mail.failed webhook fires on terminal failure.
Three flavors of the exact same form. Only the CSS layer differs. Replace YOUR_PUBLIC_ID with the id you get from /Dashboard/Forms or the MCP createFormEndpoint tool.
Get a working contact form in under 30 seconds. No backend, no SDK, no build step — grab your form public ID from Dashboard → Forms and paste it into the prompt below for your platform.
Accept: application/json to your fetch headers
and JS2Mail returns {"status":"queued"} instead of a redirect.
Perfect for SPA and React-based projects where you control the UX after submission.
We never read your inbox — connecting a mailbox is only about authorizing JS2Mail to send on its behalf. Different providers ask for different setup steps. Pick the one that matches your mailbox below.
These live on your domain's DNS — JS2Mail can't set them for you, but the receiving mail server checks them before deciding where your message lands. Most Workspace / Microsoft 365 customers already have SPF + DKIM auto-configured by their provider; custom SMTP setups usually need manual records.
v=spf1 include:_spf.google.com ~all (Gmail / Workspace) v=spf1 include:spf.protection.outlook.com -all (Microsoft 365) For custom SMTP, your hosting provider gives you the include: directive.
Gmail Workspace + Microsoft 365 both auto-generate DKIM keys you publish at default._domainkey.<your-domain>. For custom SMTP, your provider documents the selector + record.
v=DMARC1; p=none; rua=mailto:[email protected] (start with p=none + rua to monitor, tighten to p=quarantine then p=reject after a week of clean reports)
JS2Mail is built around minimal data touch. We store only what's necessary to deliver your mail, encrypted at rest, and never share it with third parties.
OAuth refresh tokens and SMTP passwords are encrypted with AES-256-GCM before being written to the database. The plaintext never touches disk. Keys are rotated quarterly and stored separately from the encrypted data.
Gmail: we request gmail.send only. Microsoft 365: Mail.Send + offline_access. We never request inbox read, contacts, calendar, or any other access beyond what's required to dispatch a message.
Send logs (status, timestamp, recipient domain) are retained for 30 days on the free plan, 90 days on paid. Message body and attachments are never stored after dispatch — we pass them through to the provider and discard them immediately.
JS2Mail acts as a data processor under GDPR — you remain the controller. Data is processed in the EU (Frankfurt). You can request full data export or account deletion at any time from Dashboard → Settings → Data. We respond within 72 hours.