How to Send Email with Python Using the Brixus365 API
Send your first email from Python in about five minutes — no SDK required, just the requests library and one HTTP POST. Covers starter templates, your own HTML, dynamic data, batch sends, and error handling.
On this page · 9
You don’t need an SDK to send email from Python with Brixus365 — the API is a plain HTTPS endpoint, so the requests library and one POST is all it takes. This guide takes you from zero to a delivered email, then to templates, dynamic data, and batch sends.
Every example below is real, copy-pasteable Python against the live /v1/emails endpoint.
Prerequisites
- Python 3.8+
- The requests library:
pip install requests - A Brixus365 API key (we’ll get one in the next step)
That’s it. No package to install from us, no client library to learn — just HTTP.
Get an API key
Create a free Brixus365 account, then generate a key under Settings → API Keys. Keys look like bx_live_…. Treat it like a password: load it from an environment variable, never hard-code it or commit it.
export BRIXUS_API_KEY="bx_live_your_key_here"
The Free plan includes 9,000 emails a month with no credit card — enough to build and ship a real integration. (Pricing.)
Your first send
The endpoint is POST https://app.brixus365.com/api/v1/emails. You authenticate with the X-API-Key header. The simplest possible send uses your own HTML:
import os
import requests
resp = requests.post(
"https://app.brixus365.com/api/v1/emails",
headers={"X-API-Key": os.environ["BRIXUS_API_KEY"]},
json={
"to": "customer@example.com",
"subject": "Your order is confirmed",
"html": "<h1>Order confirmed ✅</h1><p>Thanks — your order is on its way.</p>",
},
timeout=10,
)
resp.raise_for_status()
print(resp.json()) # → {"id": "msg_...", "status": "queued"}
A few things to note:
subjectis required when you send rawhtml. (Starter templates carry their own subject — more on that below.)- The response returns a message ID you can use to look up delivery status later.
raise_for_status()turns any non-2xx response into an exception so failures don’t pass silently.
Sending a saved template
Hard-coding HTML in your app gets unwieldy fast. Brixus365 has starter templates (ready-made, for common messages like otp, password reset, and receipts) and your own saved templates (designed in the app, referenced by ID).
A starter template — no design work, no subject needed:
requests.post(
"https://app.brixus365.com/api/v1/emails",
headers={"X-API-Key": os.environ["BRIXUS_API_KEY"]},
json={
"to": "customer@example.com",
"starterTemplate": "otp",
"data": {"code": "493021"},
},
timeout=10,
)
A custom template you built in the app — reference it by templateId:
json={
"to": "customer@example.com",
"templateId": "tmpl_abc123",
"data": {"name": "Maya", "order_id": "BX-1041"},
}
Exactly one of html, starterTemplate, or templateId should be present per send.
Personalising with dynamic data
The data object holds key-value pairs that get substituted into the template’s placeholders — {{name}}, {{order_id}}, and so on. This is how one template serves every customer:
def send_receipt(email, name, order_id, amount):
return requests.post(
"https://app.brixus365.com/api/v1/emails",
headers={"X-API-Key": os.environ["BRIXUS_API_KEY"]},
json={
"to": email,
"templateId": "tmpl_receipt",
"data": {
"name": name,
"order_id": order_id,
"amount": amount,
},
},
timeout=10,
)
Wrapping the call in a function like this is the usual pattern — your app calls send_receipt(...) the moment an order is placed.
Sending in batches
Looping POST /v1/emails works, but for many messages at once the batch endpoint is far more efficient — up to 100 messages in one call (and up to 1,000 total recipients):
requests.post(
"https://app.brixus365.com/api/v1/emails/batch",
headers={"X-API-Key": os.environ["BRIXUS_API_KEY"]},
json={
"messages": [
{"to": "a@example.com", "templateId": "tmpl_digest", "data": {"name": "Ava"}},
{"to": "b@example.com", "templateId": "tmpl_digest", "data": {"name": "Leo"}},
]
},
timeout=30,
)
Each message in the array has the same shape as a single send. For anything truly large, run the batch calls from a background worker so a slow request never blocks your web process.
Handling errors
The API returns standard HTTP status codes with a machine-readable error field. Handle the ones you’ll actually hit:
resp = requests.post(url, headers=headers, json=payload, timeout=10)
if resp.status_code == 200:
print("queued:", resp.json()["id"])
elif resp.status_code == 401:
raise RuntimeError("Bad or missing API key")
elif resp.status_code == 422:
print("Validation error:", resp.json()) # e.g. invalid 'to' address
elif resp.status_code == 429:
print("Rate limited — back off and retry")
else:
resp.raise_for_status()
Common codes: 401 missing_api_key (header absent or wrong), 400 missing_field (no template or html supplied), 404 template_not_found (unknown starter slug), 429 (too many requests — retry with backoff). Full list in the API reference.
Where to go next
- Track delivery. Each send returns a message ID; poll it (or use webhooks) to follow delivered → opened → clicked. See transactional email analytics.
- Skip the integration entirely. If you’re prototyping, the Brixus365 MCP server lets an AI assistant like Claude or Cursor send through the same API — “email this customer their receipt” — with no code at all.
- Go deeper. The full API reference covers attachments, custom
fromaddresses, scheduling, and idempotency keys for safe retries.
FAQ
Do I need an SDK to send email from Python?
Is the Brixus365 API free to use?
How do I know whether an email was delivered?
How do I send email in the background so it doesn’t slow my app?
That’s a working Python integration. Start free to grab a key — 9,000 emails a month, no card — and send your first one today.
Send smarter emails with Brixus365
Campaigns and transactional API on one engine. 9,000 emails/month free, no credit card.