Send emails with Python
Send email from Python with the official mailblastr package — zero dependencies, configured module-level like stripe or resend.
The official `mailblastr` package is the fastest way to send email from Python. It has zero dependencies (standard library urllib + json only) and is configured module-level — set mailblastr.api_key once, then call the resource classes. There is no client object to construct and pass around.
This guide sends a single email with mailblastr.Emails.send(...). The package also sets the required User-Agent header on every request for you, retries 429/503 for you, and raises typed errors instead of handing back raw HTTP.
Prerequisites
- A verified domain for your
fromaddress. (guide) - An API key (
mb_...), read fromMAILBLASTR_API_KEY. (Authentication) - Python 3.8 or newer — the package declares
requires-python >= 3.8.
Install
pip install mailblastrConfigure
Assign your key to mailblastr.api_key once, at import time or during app startup. Read it from the environment so the secret never lands in source control.
import os
import mailblastr
mailblastr.api_key = os.environ["MAILBLASTR_API_KEY"]Two more module-level knobs are optional: mailblastr.timeout (per-request seconds, default 30) and mailblastr.max_retries (automatic retries of 429/503 only, default 2; set 0 to disable). Because only those two statuses are retried, a send is never duplicated by a retry.
Send an email
Every field of the send body is a plain dict key — from is a Python keyword, so the payload is a dict rather than keyword arguments. to accepts a single address or a list.
import os
import mailblastr
mailblastr.api_key = os.environ["MAILBLASTR_API_KEY"]
email = mailblastr.Emails.send({
"from": "Acme <hello@yourdomain.com>",
"to": ["delivered@mailblastr.dev"],
"subject": "Hello from Python",
"html": "<p>Sent with the mailblastr package 🐍</p>",
})
print("Sent email", email["id"])delivered@mailblastr.dev is the MailBlastr simulator: the send is accepted, recorded, and marked delivered without touching a real inbox. Swap it for your own address once the first call succeeds — and never use @example.com, which the API rejects with 422.Handling the response
Every method returns the parsed JSON response as a dict, so a successful send gives you email["id"]. A non-2xx answer raises mailblastr.MailblastrError, which carries the { statusCode, name, message } envelope — branch on err.name, never on err.message (messages are scrubbed server-side and are not a stable contract).
import time
try:
email = mailblastr.Emails.send(params)
print("Sent email", email["id"])
except mailblastr.MailblastrError as err:
print(err.status_code, err.name, err.message)
if err.name == "daily_quota_exceeded":
# Plan/quota rejections describe the cap that was hit.
print(err.limit["used"], err.limit["limit"], err.limit["next_plan"])
if err.retry_after:
time.sleep(err.retry_after)
print(err.body) # the full parsed error bodyA transport failure (or a missing key) raises the same exception with status_code == 0 and name of network_error or missing_api_key, so one except clause covers both.
Retry safely with an idempotency key
Pass options={"idempotency_key": "..."} so replaying a request returns the original response instead of sending twice. Only Emails.send and Batch.send honour it — see Idempotency.
mailblastr.Emails.send(params, options={"idempotency_key": "order-123"})
# Up to 100 emails in one request (no attachments, no scheduled_at).
mailblastr.Batch.send([
{"from": "hello@yourdomain.com", "to": ["delivered@mailblastr.dev"], "subject": "Hi A", "html": "<p>A</p>"},
{"from": "hello@yourdomain.com", "to": ["delivered@mailblastr.dev"], "subject": "Hi B", "html": "<p>B</p>"},
], options={"idempotency_key": "orders-2026-08-19"})Schedule instead of sending now
Add scheduled_at (ISO 8601) to hand the send to the scheduler. A scheduled send goes through the real delivery path, so it cannot target the simulator address — use one of your own recipients.
scheduled = mailblastr.Emails.send({
"from": "Acme <hello@yourdomain.com>",
"to": ["you@yourdomain.com"],
"subject": "Tomorrow morning",
"html": "<p>Queued ahead of time.</p>",
"scheduled_at": "2026-09-01T09:00:00Z",
})
mailblastr.Emails.update(scheduled["id"], {"scheduled_at": "2026-09-01T14:00:00Z"}) # reschedule
mailblastr.Emails.cancel(scheduled["id"]) # or call it offmb_ API key server-side — load it from an environment variable or secrets manager, never commit it, and never ship it in a client-side script or notebook you share. Anyone holding the key can send email as you.Next steps
- See the full Send Email API reference for every body field.
- Using a web framework? See Send emails with Django.
- Explore the SDKs reference for the other resources the package exposes —
Domains,Contacts,Campaigns,Automations,Webhooks, and more. - Want no dependency at all? Python without the SDK does the same send with
requestsor stdliburllib.