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... X-JS2Mail-Delivery-Id: 3f2504e0-4f89-11d3-9a0c-... X-JS2Mail-Event-Type: MailDelivered
t = Unix timestamp of delivery.
v1 = lowercase HMAC-SHA256 hex of t + "." + body using the webhook secret.
Note the header spells the event in PascalCase
(MailDelivered)
while the JSON body's type field uses the dotted wire name
(mail.delivered). Switch on the body field.
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"
Two independent limits return 429:
a per-minute request rate limit, and your plan's monthly send quota.
POST /v1/mail/send
accepts 100 requests per minute per API key, measured as a sliding window.
Over the limit the request is rejected with 429
before it reaches the queue — nothing is enqueued, so retrying the same call is safe.
This limit is separate from the monthly quota below. Both surface as
429,
but a rate-limit rejection clears within a minute while a quota rejection lasts until the next billing period.
A blocked subscription (unpaid, canceled, or expired trial) also returns
429
with an explanatory message — check the response body to tell them apart.
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 3 attempts with exponential backoff (30s → 60s).
Auth-class provider errors (expired or revoked mailbox token) skip the retry queue and fail immediately, so the
“reconnect this mailbox” signal surfaces right away. Each transient failure emits
mail.deferred;
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:dmarc@yourdomain.com (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. The master key lives in the deployment environment, never in the database, and every encrypted value carries a version tag so keys can be rotated without re-encrypting by hand.
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, recipients, subject) are kept for the life of your workspace — deleting the workspace removes them. Message bodies are purged the moment a send succeeds: the body is stored on the queued row only so a retry can resend it, then dropped when the send reaches Sent. Failed and deferred sends keep their body so you can see what went wrong.
JS2Mail acts as a data processor — you remain the controller. Data is processed and stored in Istanbul, Türkiye. If your compliance posture requires EU-only processing, talk to us before you integrate. You can delete your workspace and everything in it at any time from Dashboard → Settings → Danger zone; for a data export, email support@js2mail.dev.