# Replit send email: an HTTPS API through your own SMTP

> Send email from a Replit app over HTTPS: a Node.js or Python route with the key in Replit Secrets, production secrets, and a form option for static apps.

Source: https://formsmtp.com/guides/replit-send-email · Last updated November 3, 2026

## SMTP or an HTTPS API?

Replit’s documentation doesn’t list outbound SMTP ports as blocked, so an SMTP library may work. An HTTPS API is still the simpler choice: it’s the same kind of request your app already makes to other services, there’s no SMTP password stored in your Replit project, and you get a clear JSON error when something fails. Replit also limits how many outgoing connections an app can open in a given period, which favors one quick HTTPS request over holding SMTP sessions open.

FormSMTP gives you that HTTPS API while still sending through your own SMTP account, so the email comes from your Gmail, Google Workspace, Microsoft 365, Zoho or hosting mailbox. Replit Agent also has connectors for several email services; FormSMTP is the option for any mailbox with SMTP access.

## 1. Create a FormSMTP project

[Sign up free](https://app.formsmtp.com/#/signup) and add a project. Pick your email provider so the SMTP host and port fill in, enter your login, and click *Test connection*. Any mailbox with SMTP access works: [Gmail or Google Workspace](https://formsmtp.com/guides/gmail-smtp-contact-form), [Microsoft 365](https://formsmtp.com/guides/outlook-smtp-contact-form), [Zoho](https://formsmtp.com/guides/zoho-smtp-contact-form), your web host’s mailbox, or a sending service. Personal Outlook.com and Hotmail addresses can’t be used, because Microsoft only lets them sign in with OAuth.

In *Settings → Security*, set **Allowed recipients** to your own address if the app only notifies you, or to your users’ domain (for example `@yourcompany.com`) if it emails a known group. Set **Max API emails per hour** to what you expect to send. Copy the **API key** (it starts with `fs_`).

## 2. Store the key in Replit Secrets

Open **Secrets** in your project, select **New Secret**, and add `FORMSMTP_API_KEY` with your API key. Replit encrypts it and exposes it to your code as an environment variable. You can also ask Replit to open its secure secret form; either way, keep the key out of chat messages and Git.

Secrets you add in the editor don’t carry over to your published app. Add `FORMSMTP_API_KEY` again in the **Publishing** pane. Secrets aren’t available to Static deployments at all; see the form option below.

## 3. Add a route that sends the email

A small contact endpoint for your app. It emails you, uses the visitor’s address as reply-to, and drops bots that fill in a hidden field. Replit passes the port to use in the `PORT` environment variable.

```js
// index.js (npm install express)
import express from "express";

const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static("public"));

async function sendEmail(message) {
  const res = await fetch("https://app.formsmtp.com/api/v1/send", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.FORMSMTP_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(message),
  });
  const data = await res.json();
  if (!data.success) throw new Error(data.error);
  return data.messageId;
}

app.post("/api/contact", async (req, res) => {
  const { name, email, message, website } = req.body;
  if (website) return res.json({ ok: true }); // honeypot
  if (!name || !email || !message) return res.status(400).json({ ok: false, error: "Please fill in every field." });
  try {
    await sendEmail({
      to: "you@yourdomain.com",
      replyTo: email,
      subject: `New message from ${name}`,
      text: message,
    });
    res.json({ ok: true });
  } catch (err) {
    console.error("FormSMTP:", err.message); // the details stay in your logs
    res.status(502).json({ ok: false, error: "Sorry, your message couldn't be sent. Please try again later." });
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, "0.0.0.0", () => console.log(`Listening on ${PORT}`));
```

```python
# main.py (pip install flask requests)
import os

import requests
from flask import Flask, jsonify, request

app = Flask(__name__, static_folder="public", static_url_path="")

def send_email(message):
    res = requests.post(
        "https://app.formsmtp.com/api/v1/send",
        headers={"Authorization": f"Bearer {os.environ['FORMSMTP_API_KEY']}"},
        json=message,
        timeout=30,
    )
    data = res.json()
    if not data.get("success"):
        raise RuntimeError(data.get("error"))
    return data["messageId"]

@app.post("/api/contact")
def contact():
    form = request.get_json(silent=True) or request.form
    if form.get("website"):  # honeypot
        return jsonify(ok=True)
    name, email, message = form.get("name"), form.get("email"), form.get("message")
    if not (name and email and message):
        return jsonify(ok=False, error="Please fill in every field."), 400
    try:
        send_email({
            "to": "you@yourdomain.com",
            "replyTo": email,
            "subject": f"New message from {name}",
            "text": message,
        })
        return jsonify(ok=True)
    except Exception as err:
        app.logger.error("FormSMTP: %s", err)  # the details stay in your logs
        return jsonify(ok=False, error="Sorry, your message couldn't be sent. Please try again later."), 502

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 3000)))
```

The same `sendEmail()` call works for anything else your app sends: welcome emails, receipts, alerts. Just change `to`, and make sure Allowed recipients covers it.

## 4. Test, then publish

Point your page’s form at `/api/contact` (a plain `<form method="POST" action="/api/contact">` works, or a `fetch()` call that sends JSON), open the Preview and send yourself a message. It arrives from your own address and shows up under *Logs* in FormSMTP.

When it works, open **Publishing**, choose **Autoscale** or **Reserved VM** (they run a server; Static doesn’t), add `FORMSMTP_API_KEY` to the production secrets, and publish. Check the Logs tab in the Publishing pane if anything fails.

## Static deployment? Use the form endpoint

A Static deployment serves files only and can’t read Secrets, so it can’t hold an API key. Post the form straight to FormSMTP with the public form key instead. Set *Allowed websites* to `https://your-app.replit.app` and any custom domain, and *Allowed recipients* to your address.

```html
<form action="https://app.formsmtp.com/api/v1/form/YOUR_FORM_KEY" method="POST">
  <label>Name <input name="name" required></label>
  <label>Email <input name="email" type="email" required></label>
  <label>Message <textarea name="message" rows="5" required></textarea></label>
  <input type="hidden" name="_subject" value="New message from my Replit site">
  <input type="text" name="_gotcha" style="display:none" tabindex="-1" autocomplete="off">
  <button type="submit">Send message</button>
</form>
```

Want an inline “Thanks!” message instead of a thank-you page? See the [JavaScript guide](https://formsmtp.com/guides/send-email-from-javascript).

## Troubleshooting

- **Works in the editor, fails when published.** The production deployment doesn’t have `FORMSMTP_API_KEY`. Add it in the Publishing pane and republish.
- **“Missing API key”.** The environment variable is empty: check the secret’s exact name, and that you’re not on a Static deployment.
- **“That is a form key”.** You used the `fk_` key with `/send`. Server code needs the `fs_` API key.
- **“Recipient not allowed for this project”.** The `to` address isn’t covered by Allowed recipients.
- **A 502 with an SMTP message.** Your mail server refused the message, and the error says why. Usually it’s the password (Gmail needs an App Password) or a From address that doesn’t match the account.

## FAQ

### Can Replit send emails?

Yes. Any Replit app with a server can call an email API over HTTPS. With FormSMTP, that call sends through your own SMTP account, so the email comes from your own address.

### Does Replit block SMTP ports?

Replit’s documentation doesn’t say so. We still recommend an HTTPS API: it uses the same kind of connection as the rest of your app, and your SMTP password never has to live in your Replit project.

### Can I send from my Gmail account?

Yes. Connect Gmail in FormSMTP with an App Password (see the [Gmail guide](https://formsmtp.com/guides/gmail-smtp-contact-form)), and your Replit app sends through it via the API.

### Is the free plan enough?

For notifications and contact forms, usually. FormSMTP’s free plan includes 1,000 emails a month, and Pro is $5 a month for 50,000.

## More guides

- [Webflow form to email: custom action with your SMTP](https://formsmtp.com/guides/webflow-contact-form)
- [Framer form to email: webhook or code component](https://formsmtp.com/guides/framer-contact-form)
- [Carrd contact form that emails you from your address](https://formsmtp.com/guides/carrd-contact-form)
- [Lovable contact form that sends email via your SMTP](https://formsmtp.com/guides/lovable-contact-form)
