Skip to content

Changelog

Changes that affect the public API or the SDKs are listed here. SDK packages follow semantic versioning; their detailed changelogs are published with each npm release.

Security hardening: public API edge and keys (September 2026)

Section titled “Security hardening: public API edge and keys (September 2026)”

Behavior changes – please check your integration:

  • Requests without Origin and Referer (servers, curl, native apps) with the public key now need Allow mobile apps – also when your allowed-websites list is empty. Before, an empty list accepted them. Organizations that sent such requests in the last 30 days had the switch turned on automatically. Otherwise: 403 origin_not_allowed (details.reason: "no_origin"). On servers, use a private key.
  • Private keys from browsers are refused: a private-key request (Authorization: Bearer or the EmailJS-style accessToken field) that carries an Origin header gets the new error 403 private_key_in_browser. Opt-in for internal tools: Security → Allow private keys in browsers.
  • CAPTCHA for requests without Origin is verified with Frontmail’s shared mobile widget only when Allow mobile apps is on. Cloudflare test keys are refused in production.
  • Status polling: send the status token in the X-Frontmail-Status-Token header; ?token= keeps working for older SDKs.
  • Rate limits: IPv6 clients share the per-IP limit per /64 network. The per-key/per-organization limits and anomaly detection now count only requests that passed the template and CAPTCHA checks, so a flood of invalid requests no longer blocks your real visitors.
  • Attachments: file names are cleaned (invisible/bidi characters, trailing dots) and more dangerous types are refused (HTML, SVG, disk images, OneNote, macro-enabled Office, .url, .lnk, …). Public-key uploads (POST /v1/uploads) need a template that accepts attachments and have a daily byte budget per organization.
  • Multipart template_id / service_id over 64 characters → 400 invalid_body (was 500).
  • The API, dashboard API and sign-in only accept traffic that comes through Frontmail’s CDN.
  • POST /v1/send, /v1/send-form, /v1/send-batch, /v1/uploads, GET /v1/messages/:id, GET /v1/history, GET /v1/templates and EmailJS-compatible aliases.
  • Unified error format with docs_url; Idempotency-Key support (24 h).
  • Hold queue with held / held_service_error statuses and hold / reject modes.
  • Content lock for public-key sends to templates with a dynamic recipient: CAPTCHA required (dynamic_recipient_requires_captcha), fixed sender fields (dynamic_field_not_allowed), no HTML params and texts ≤ 500 characters, links only to allowed domains (link_not_allowed) and at most 5 emails per recipient per day. A From address from params is rejected for every public-key send. Auto-replies are locked too. New settings: security.allowedLinkDomains, security.recipientDailyLimit, template enforceLinkAllowlist. See Link allowlist & content lock.
  • @frontmail/browser 0.x (ESM + UMD, pin the version with SRI), @frontmail/react, @frontmail/react-native, @frontmail/vue, @frontmail/svelte, @frontmail/node with the frontmail types CLI, @frontmail/emailjs-compat.
  • Automatic retries with exponential backoff and idempotency keys; typed errors.
  • Two-step verification is now required for every sign-in method – emailed sign-in links and Google / GitHub included – and can only be turned on with a verified email address.
  • Sign-in and verification links opened in a different browser ask for confirmation (or don’t sign that browser in), so a link sent by someone else can’t sign you in to their account.
  • Changing the sign-in email needs your password and approval from the current address.
  • Admins can no longer grant the Billing role; only the owner manages admins and billing members.
  • Provider webhook URLs are hidden from viewers and billing members and can be regenerated (Generate new webhook URL).
  • Custom SMTP servers must use a public address and port 25, 465, 587 or 2525.
  • Template attachments can only use files uploaded by the same organization.
  • Team invitations are limited per recipient and organization; organization names can’t contain links.
  • Click tracking data exported to analytics no longer contains query strings (tokens, emails).

SDK security hardening (next SDK release, 0.2.0)

Section titled “SDK security hardening (next SDK release, 0.2.0)”
  • Breaking: the browser SDKs (@frontmail/browser, React, Vue, Svelte, @frontmail/emailjs-compat) throw private_key_in_browser when a private key (privateKey, compat accessToken) is used in a web browser; @frontmail/node refuses to run there. Opt-out: dangerouslyAllowPrivateKeyInBrowser: true.
  • sendForm skips password inputs, anti-CSRF fields and reserved names; new formFields: { include, exclude }.
  • getStatus sends the status token in the X-Frontmail-Status-Token header instead of ?token=.
  • React Native <TurnstileWebView> is locked to the widget page (origins, navigation, messages).
  • CDN: sri.json with integrity hashes next to every versioned bundle; docs use version-pinned URLs with Subresource Integrity.
  • HTML template editor with live preview, typed params, checks, versions and gallery (EN/CS).
  • Services for SMTP, Mailgun, Amazon SES, Postmark, SendGrid, Mailjet, Brevo, Resend, Gmail and Outlook / Microsoft 365, with failover and health checks.
  • Credits: plans, credit packs, overdraft, auto top-up; usage statistics.
  • Yearly plans now get their monthly quota and overdraft buffer in every month of the period (previously only the first month).
  • Overdraft used on yearly plans is billed monthly as a separate invoice; overdraft used before a subscription ends (cancellation, organization deletion) is billed right away.
  • Monthly → yearly switches carry over the credits used in the current month.
  • Plan changes are refused while the subscription has an unpaid invoice (409 conflict, details.reason: "subscription_not_active").
  • Disputed (charged-back) payments remove the credits they bought; they are restored if the dispute is won. Refunds are processed per refund.
  • New: the hold queue is limited per organization; beyond the limit requests get 402 insufficient_credits with details.reason: "hold_queue_full".
  • New: emails sent with the public key don’t use the overdraft or trigger auto top-up unless enabled in Billing → Buy credits → Spending by public-key traffic (off by default, also for existing organizations).
  • Custom SMTP servers: failures after the server received the message are no longer refunded; a per-organization refund-rate guard stops refunds when failures are abnormally frequent.
  • Provider webhooks suppress only actual recipients of the message; Amazon SES webhooks pin the SNS topic of the first signed message. Resend refuses templates frozen by a downgrade.