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:
export SECURESSMTP_API_KEY="qcs_live_..."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
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_tois the visitor’s address, so you can answer with Reply in your email program.source_pluginis a label shown in the email log.- The route accepts both JSON and normal form posts, and limits the input before sending.
"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.
| Response | Meaning | What to do |
|---|---|---|
200 ok: true | Accepted for sending. | Nothing. Keep message_id if you want to find the email later. |
200 rate_limited | More than 120 sends from this site in 60 seconds. | Wait a minute, then try again. |
200 over_quota | The 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_failed | The 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_flagged | The content was judged to be spam. | Change the content. See Deliverability. |
401 missing_api_key, invalid_api_key | No key was sent, or the key is wrong or was rotated. | Check the environment variable on the server. |
403 site_disabled | The site is disabled. | See Blocks. |
- Check
okin 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
# 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}[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
- Spam protection for forms: Spam protection.
- Every field and response: POST /mail/send.