Notix
Integrations

Email from a Flask app, sent and confirmed.

Flask keeps it small: one notix-sdk client created alongside the app, one view that sends, and one view that receives delivery events. request.data holds the raw bytes the signature check needs.

The send

Send an email from Flask.

app.py
import os
from flask import Flask, request
from notix import Notix

app = Flask(__name__)
notix = Notix(os.environ["NOTIX_API_KEY"])

@app.post("/orders/<int:order_id>/receipt")
def send_receipt(order_id: int):
    to = request.form["email"]
    resp, _ = notix.emails.send(
        payload={
            "from": "Acme <receipts@acme.com>",
            "to": to,
            "subject": "Your receipt",
            "html": "<p>Thanks for your order.</p>",
        },
        options={"idempotency_key": f"order-{order_id}-receipt"},
    )
    return {"id": resp["emailId"]}

The from address must be on a domain you have verified in Notix. Step by step: the Python quickstart and the longer guide to sending email from Flask.

Environment

One API key, kept on the server.

Create an API key on the API keys page of the Notix console and store it as NOTIX_API_KEY in the environment the app starts with. Read it only in code that runs on the server, never in anything shipped to a browser.

A Send only key is enough for code that only sends: if it leaks, it cannot read your contacts or delete a domain.

.env
NOTIX_API_KEY=notix_xxxxxxxxxxxx
NOTIX_WEBHOOK_SECRET=whsec_xxxxxxxxxxxx
Webhooks

Verify delivery events over the raw body.

Notix signs every webhook call with the webhook's signing secret: an HMAC-SHA256 of the X-Notix-Timestamp header, a dot and the raw body, sent in X-Notix-Signature. The SDKs check the signature and refuse a call more than 5 minutes old.

Pass the request body as bytes, before any JSON parsing: the signature covers the exact bytes Notix sent. A bad call raises WebhookVerificationError; answer 400.

app.py
from notix import WebhookVerificationError

webhooks = notix.webhooks(os.environ["NOTIX_WEBHOOK_SECRET"])

@app.post("/webhooks/notix")
def notix_webhook():
    try:
        event = webhooks.construct_event(request.data, headers=request.headers)
    except WebhookVerificationError:
        return "invalid signature", 400
    return "ok", 200
FAQ

Questions, answered.

Can I use Flask-Mail with Notix instead?
Yes. Flask-Mail sends over SMTP, so set its server to smtp.usenotix.dev on port 465 with SSL or 587 with TLS, the username notix and your API key as the password.
What if the same request runs twice?
Send an Idempotency-Key header (idempotencyKey in notix-js) with a value that names the thing being sent, such as order-4471-receipt. A repeat with the same key and body returns the first result and sends nothing new; the same key with a different body is refused with 409.
Why is my send refused with a from-address error?
The from address must be on a domain you have verified in Notix. Add the domain in the console, publish the DNS records it shows, and wait for verification; until then, sends from that domain are refused.

The free plan does not ask for a card.

Send your first email in five minutes.

Verify a domain, copy an API key, make one call. The free plan does not ask for a card.