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.
Unreleased – public beta
Section titled “Unreleased – public beta”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
OriginandReferer(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: Beareror the EmailJS-styleaccessTokenfield) that carries anOriginheader gets the new error403 private_key_in_browser. Opt-in for internal tools: Security → Allow private keys in browsers. - CAPTCHA for requests without
Originis 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-Tokenheader;?token=keeps working for older SDKs. - Rate limits: IPv6 clients share the per-IP limit per
/64network. 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_idover 64 characters →400 invalid_body(was500). - 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/templatesand EmailJS-compatible aliases.- Unified error format with
docs_url;Idempotency-Keysupport (24 h). - Hold queue with
held/held_service_errorstatuses andhold/rejectmodes. - 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, templateenforceLinkAllowlist. See Link allowlist & content lock.
@frontmail/browser0.x (ESM + UMD, pin the version with SRI),@frontmail/react,@frontmail/react-native,@frontmail/vue,@frontmail/svelte,@frontmail/nodewith thefrontmail typesCLI,@frontmail/emailjs-compat.- Automatic retries with exponential backoff and idempotency keys; typed errors.
Security
Section titled “Security”- 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) throwprivate_key_in_browserwhen a private key (privateKey, compataccessToken) is used in a web browser;@frontmail/noderefuses to run there. Opt-out:dangerouslyAllowPrivateKeyInBrowser: true. sendFormskips password inputs, anti-CSRF fields and reserved names; newformFields: { include, exclude }.getStatussends the status token in theX-Frontmail-Status-Tokenheader instead of?token=.- React Native
<TurnstileWebView>is locked to the widget page (origins, navigation, messages). - CDN:
sri.jsonwithintegrityhashes next to every versioned bundle; docs use version-pinned URLs with Subresource Integrity.
Dashboard
Section titled “Dashboard”- 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.
Billing & credits (security fixes)
Section titled “Billing & credits (security fixes)”- 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_creditswithdetails.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.