Limited-time offer The first 2,000 users get 10,000 emails/month free forever 2,000 of 2,000 spots left Claim yours

Documentation

FormSMTP docs

Everything you need to send email from a website through your own SMTP account.

Quickstart

  1. Create an account at app.formsmtp.com. Email and password, Google or GitHub.
  2. Add a project for your site and connect your SMTP account. Choose your provider (Gmail, Zoho, Outlook, SES…) and the host and port fill in. Click Test connection.
  3. Copy your API key from API & code, then use the HTML form below or call the JSON API.

That's it. Every send shows up under Logs with its status and, if something fails, the exact error from your SMTP server.

HTML form endpoint

The fastest way to add a working contact form: no JavaScript, no backend. Point a regular form at your project's form URL.

html
<form action="https://app.formsmtp.com/api/v1/form/YOUR_API_KEY" method="POST">
  <input name="name" required>
  <input name="email" type="email" required>
  <textarea name="message" required></textarea>

  <!-- optional -->
  <input type="hidden" name="_subject" value="New message from my site">
  <input type="hidden" name="_next" value="/thanks.html">
  <input type="text" name="_gotcha" style="display:none" tabindex="-1" autocomplete="off">

  <button>Send</button>
</form>

Every field is included in the email. The message goes to you: the first address under Allowed recipients, or the project's From address. A visitor can never choose who receives it, so the key is safe in public HTML.

Special fieldWhat it does
_subjectSubject line. Default: "New form submission from ".
_nextWhere to send the visitor after a successful submit. Must be on the same site as the form; otherwise a thank-you page is shown.
_replytoReply-to address. If absent, a field named email is used, so replying answers the visitor.
_toPick one of several inboxes. Only used if it matches your Allowed recipients.
_gotchaHoneypot. Keep it hidden; if a bot fills it, the submission is silently dropped.

Send Accept: application/json (or a JSON body) to get a JSON response instead of a page, which is handy for fetch(). File uploads (multipart/form-data) aren't supported.

Send API

POST https://app.formsmtp.com/api/v1/send with your key as Authorization: Bearer <key> (or X-API-Key).

bash
curl -X POST https://app.formsmtp.com/api/v1/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"someone@example.com","subject":"Hello","html":"<p>It works!</p>"}'
FieldDescription
to *Recipient(s): "a@x.com", "Name <a@x.com>", comma-separated, or an array.
subject *Subject line. Optional when the template has one.
html / text *Body. At least one, unless you use template.
templateName or id of a template from the dashboard. Fills subject and body.
variablesObject for the template’s {{variables}}.
cc, bccSame format as to. Max 50 recipients in total.
replyToReply-to address, for example the visitor’s email.
fromNameDisplay name override. The address is always your project’s From email.
attachments[{ "filename", "content": "<base64>", "contentType" }]. 15 MB request limit.

Templates & variables

Design emails in the visual builder (or paste HTML) and send them by name. Use {{variable}} anywhere, with an optional fallback: {{first_name|there}}.

json
{
  "to": "ana@example.com",
  "template": "Welcome",
  "variables": { "first_name": "Ana", "login_url": "https://example.com/login" }
}

If the recipient is one of your contacts, their name, email and custom fields are filled in automatically, along with {{unsubscribe_url}}.

Contacts API

POST https://app.formsmtp.com/api/v1/contacts adds or updates a contact. Perfect for a newsletter or waitlist form.

js
await fetch("https://app.formsmtp.com/api/v1/contacts", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
  body: JSON.stringify({
    email: "ana@example.com",
    name: "Ana Silva",
    tags: ["newsletter"],
    fields: { plan: "pro" },
  }),
});

Then email a tag, everyone, or specific people from Emails: now, at a set time, or on a daily, weekly or monthly schedule. Each person gets a personal copy with a working unsubscribe link.

Keeping a public key safe

Keys used in browser code are visible to anyone, so lock them down under Settings → Security:

  • Allowed websites: only these origins may call the API from a browser (for example https://yoursite.com).
  • Allowed recipients: only these addresses or @domains can receive email. For a contact form, list just yourself.
  • Max emails per hour: caps how much a copied key can send.

Origin checks only stop browsers. A script can fake an Origin header, which is why the recipient list and hourly limit matter most. For server-side code, leave Allowed websites empty and keep the key in an environment variable.

Responses & errors

Success: 200 {"success": true, "messageId": "…"}. Errors: {"success": false, "error": "…"} with:

StatusMeaning
400Invalid request: missing or malformed fields.
401Missing or wrong API key.
403Website or recipient not allowed, or the project is turned off.
404Template name not found.
429Hourly limit reached. A Retry-After header says when to try again.
502Your SMTP server refused or failed. The message says why (for example, wrong password).

SMTP settings

Common providers. The dashboard fills these in when you pick one.

ProviderSettings
Gmail / Google Workspacesmtp.gmail.com, port 465, SSL. Needs an App Password.
Outlook / Microsoft 365smtp.office365.com, port 587, STARTTLS.
Zoho Mailsmtp.zoho.com, port 465, SSL. See the Zoho guide.
Amazon SESemail-smtp.<region>.amazonaws.com, port 587, SMTP credentials from the SES console.
Brevosmtp-relay.brevo.com, port 587.
Resendsmtp.resend.com, port 465, user resend, password = your Resend API key.
Spacemailmail.spacemail.com, port 465, SSL.

Ship your form in five minutes

Connect the SMTP account you already have, copy one snippet, done. Free, no card.