How to Send Email with Python Using the Brixus365 API | Brixus365 Blog
Back to Blog
Guides9 min read

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.

Brixus365 TeamReviewed and edited by the Brixus365 team
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:

  • subject is required when you send raw html. (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 from addresses, scheduling, and idempotency keys for safe retries.

FAQ

Do I need an SDK to send email from Python?
No. The Brixus365 API is a plain HTTPS endpoint, so the requests library and a single POST is all you need — there’s no client library to install or learn, and nothing extra to keep up to date.
Is the Brixus365 API free to use?
Yes. The Free plan includes 9,000 emails a month with no credit card — enough to build and run a real integration. You only pay once your volume grows.
How do I know whether an email was delivered?
Every send returns a message ID. You can look that ID up for its delivery status, or subscribe to webhooks to receive delivered, opened, clicked, and bounced events as they happen.
How do I send email in the background so it doesn’t slow my app?
Move the send into a background worker or task queue so your web request returns immediately. The API call itself is fast, but offloading it keeps your app responsive under load or if a network call is slow.

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.

SharePost on XLinkedIn
Try it free

Send smarter emails with Brixus365

Campaigns and transactional API on one engine. 9,000 emails/month free, no credit card.

Start sending free
9,000 emails/month freeNo credit card required
All articles →
Stay in the loop

New guides, straight to your inbox

Field notes on deliverability, list hygiene, and transactional email — roughly once a month, no fluff.

No spam. Unsubscribe with one click. We respect your inbox.