INTEGRATIONS · Published 2026-10-06 · Updated 2026-10-06 · SecureSMTP

Flask

A contact route that sends through SecureSMTP.

A POST /contact route that checks the input and sends it to you as an email through the API. Flask 2.0 or later.

Setup

Every request needs your site’s API key. Get it when you add the site under Sites (/app/forms/sites) in the dashboard — see Sites and API keys. Keep it in an environment variable on the server:

Shell
export SECURESSMTP_API_KEY="qcs_live_..."
Never put the key in browser JavaScript, a mobile app or a public repository. Anyone who has it can send email as your site.

Copy securessmtp.py from the Python guide next to app.py. It has the send_email function used below and needs nothing outside the standard library.

The contact route

app.py
# app.py
import re

from flask import Flask, jsonify, request

from securessmtp import SecureSMTPError, send_email

app = Flask(__name__)

EMAIL_RE = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")
CONTACT_TO = "[email protected]"


@app.post("/contact")
def contact():
    data = request.get_json(silent=True) or request.form
    name = str(data.get("name", "")).strip()
    email = str(data.get("email", "")).strip()
    message = str(data.get("message", "")).strip()

    if not name or len(name) > 100 or not EMAIL_RE.match(email) or not message or len(message) > 5000:
        return jsonify(ok=False, error="Please fill in every field."), 422

    try:
        send_email({
            "to": CONTACT_TO,
            "subject": f"Contact form: {name}",
            "text": f"Name: {name}\nEmail: {email}\n\n{message}",
            "from": {"name": "Website contact form"},
            "reply_to": email,
            "source_plugin": "flask-contact",
        })
    except SecureSMTPError as err:
        app.logger.error("Contact email failed: %s %s", err.reason, err.result.get("error", ""))
        return jsonify(ok=False, error="Could not send your message. Please try again later."), 502
    except OSError as err:  # network errors and timeouts
        app.logger.error("Could not reach SecureSMTP: %s", err)
        return jsonify(ok=False, error="Could not send your message. Please try again later."), 502

    return jsonify(ok=True)
  • reply_to is the visitor’s address, so you can answer with Reply in your email program.
  • source_plugin is a label shown in the email log.
  • The route accepts both JSON and normal form posts, and limits the input before sending.
The route has no spam protection of its own. Add a rate limit per IP and a captcha, or use the Forms API, which has both. A contact-form notification that SecureSMTP judges to be spam is held: the API answers "ok": true, "held": true and the email is not sent.

Handle errors

send_email raises SecureSMTPError with the API’s reason. Network errors and timeouts raise OSError subclasses. The route logs both and returns 502.

ResponseMeaningWhat to do
200 ok: trueAccepted for sending.Nothing. Keep message_id if you want to find the email later.
200 rate_limitedMore than 120 sends from this site in 60 seconds.Wait a minute, then try again.
200 over_quotaThe account’s monthly email count is used up (relay mode only).Wait for the new month, upgrade, or send from a verified domain.
200 send_failedThe email was not sent. The error field says why.Read error. Do not retry in a loop.
400 invalid_payload, no_body, …The request is wrong. details lists the fields for invalid_payload.Fix the request. Retrying the same request fails the same way.
400 content_flagged, ai_flaggedThe content was judged to be spam.Change the content. See Deliverability.
401 missing_api_key, invalid_api_keyNo key was sent, or the key is wrong or was rotated.Check the environment variable on the server.
403 site_disabledThe site is disabled.See Blocks.
  • Check ok in the body, not only the HTTP status. Rate limit, monthly limit and send failures come back with HTTP 200.
  • There is no idempotency key. If a request times out, the email may already have been sent, and sending it again can deliver it twice.
  • Every reason is listed in the error catalogue.

Or use SMTP with Flask-Mail

app.py
# pip install Flask-Mail
import os

from flask import Flask
from flask_mail import Mail, Message

app = Flask(__name__)
app.config.update(
    MAIL_SERVER="smtp.securessmtp.com",
    MAIL_PORT=587,
    MAIL_USE_TLS=True,
    MAIL_USERNAME="securessmtp",
    MAIL_PASSWORD=os.environ["SECURESSMTP_API_KEY"],
    MAIL_DEFAULT_SENDER=("Acme Store", "[email protected]"),
)
mail = Mail(app)


@app.post("/send-receipt")
def send_receipt():
    mail.send(Message(
        subject="Your receipt",
        recipients=["[email protected]"],
        body="Thanks for your order.",
    ))
    return {"ok": True}
In relay mode (no verified domain) the From address is replaced: the email goes out from [email protected] with your From name, and the From address you set becomes the Reply-To. Verify your domain and the email goes out from your own address. See Domains and DNS.

Flask-Mail uses smtplib, so a refused email raises an smtplib exception with the SMTP reply code. See the SMTP guide for the codes.

Next