Skip to content

Troubleshooting

Start with the error code: every API error includes code and docs_url, and Error codes explains each one. History shows every accepted message with its timeline, the provider response and the rendered content.

403 origin_not_allowed – Add your site’s domain to Security → Allowed websites (and localhost for development). Check the exact host, including www.. With details.reason: "no_origin" the request had no Origin at all (native app, server script): turn on Allow mobile apps for apps, use a private key on servers. See Allowed origins.

403 private_key_in_browser – A private key was used from a web page. Use the public key in the browser and keep the private key on your server. See Keys.

403 captcha_required / captcha_failed – The template requires Turnstile. Render the widget inside the form or pass turnstileToken; reset the widget after each attempt, because tokens are single-use. captcha_failed with hostname_mismatch means the widget was solved on a hostname that isn’t the request’s origin – add every hostname of your site to your Turnstile widget. See Turnstile.

403 captcha_not_configured – The template requires the CAPTCHA, but your organization hasn’t added its own Turnstile keys. Create a free widget in Cloudflare and paste its site key and secret key into Security → Bot protection (Turnstile), or turn the CAPTCHA off on the template.

422 invalid_template_params – Look at details.issues: each issue names the param and the rule. Common causes: a required field is empty, an email param got a name, a number param got "12 pcs", a list param got a string that isn’t JSON.

403 dynamic_recipient_not_allowed – The template’s To/CC/BCC uses a param. Use an auto-reply for confirmations, or enable Allow dynamic recipient in the template’s Settings → Protection.

429 rate_limited – You exceeded the plan, IP or key rate. The SDK already waited and retried. For bulk sends from a server, use batch sends.

CORS error in the browser console – Usually a different error in disguise: the request was blocked by a Content-Security-Policy (connect-src), an ad blocker, or went to a wrong apiUrl. The Frontmail API sends CORS headers for all origins; access is controlled by allowed origins.

  1. Find the message in History.
    • held – you are out of credits. Buy a pack (Buy credits) or wait for renewal; it will be sent automatically. It is also listed in Held messages. See Hold queue.
    • held_service_error – your service’s credentials stopped working. Open Email services, fix or reconnect the service; held messages are sent automatically afterwards.
    • failed – open the message: the provider’s error is shown in the timeline. Typical causes are an unverified sender domain or an invalid recipient.
    • sent – the provider accepted it. Continue below.
  2. Check spam. If it’s there, set up SPF, DKIM and DMARC for your From domain as described in your provider guide, and use a From address on that domain (not a @gmail.com address through a transactional provider).
  3. Check the suppression list. Sends to suppressed addresses fail with 451, but if you removed the address from the list after a bounce, the mailbox may still not exist.
  4. Set up webhooks to see delivered / bounced events instead of guessing.
  • Gmail: Google revokes refresh tokens when the password changes, when the user removes the app’s access, or after 6 months without use. Reconnect the service.
  • API providers: the key was rotated or its permissions reduced. Create a key with send permission and update the service.
  • SMTP: the mailbox password changed, or the provider requires an app password when 2FA is on.

Add a fallback service so a broken service doesn’t stop your forms while you fix it.

  • Styles missing in Gmail or Outlook → enable Inline CSS on save in the template’s Settings.
  • Text is cut off with “View entire message” → the email is over ~100 kB; remove inline images or large styles.
  • Literal <b> in the email → the value was escaped. Use an html param if you really need markup (see escaping).
  • Dates in the wrong language or time zone → set the template locale and your organization time zone, or pass timeZone= to formatDate.

Email support@frontmail.dev with the message_id (or the code and time of the error). Never include your private key.