Guide
How to send email with Python
Send email from Python with requests and the REST API.
In short
Create a Sendpository account, verify your domain, put your API key inSENDPOSITORY_API_KEY, and send with the code below - one HTTPS request per email, from server-side code only.1. Verify your sending domain
Add your domain in the dashboard and publish the three DNS records it shows - SPF and a bounce record on an sp. subdomain, and a DKIM key on your apex. Your existing records are never edited. Verification usually lands in a few minutes, and you can set up the code below while you wait.
2. Create a key
Create an API key with the sending permission. It is shown once, so put it straight into your secrets. Export SENDPOSITORY_API_KEY in your shell or process manager.
3. Install
pip install requests
4. Send an email
import os
import requests
res = requests.post(
"https://api.sendpository.com/v1/emails",
headers={"Authorization": f"Bearer {os.environ['SENDPOSITORY_API_KEY']}"},
json={
"from": "Your App <hello@mail.yourdomain.com>",
"to": ["customer@example.com"],
"subject": "Your receipt",
"html": "<p>Thanks for your order.</p>",
},
timeout=10,
)
res.raise_for_status()
print(res.json()["id"])A success returns { "id": "..." } - the message’s id for looking it up later. A failure returns { "error": { "type", "message" } } with a 4xx or 5xx status.
Where the send belongs
In a background thread or a task queue for anything a user is waiting on. `requests` is synchronous, so a call in the request path blocks that worker until the API answers.
Always pass a timeout. `requests` waits forever by default, and one unreachable upstream with no timeout will exhaust a thread pool.
Testing it
- Set `SENDPOSITORY_API_KEY` in the process environment rather than a literal - a key in source is a key in your git history.
- `response.raise_for_status()` turns a 4xx into an exception you can catch; without it a failed send looks exactly like a successful one.
Things to know
- Always pass a timeout to requests - the default waits forever.
- On a 4xx, res.json()['error']['type'] says what to fix; don't retry those.
Questions
Why does my Python send hang?
Almost always a missing timeout - `requests` waits indefinitely by default. Pass `timeout=` on every call; without it one unreachable upstream will occupy a worker thread until the process restarts.
How do I send email with Python?
Verify your sending domain, create an API key, put it in an environment variable, and POST the message as JSON to https://api.sendpository.com/v1/emails from server-side Python code. The example on this page runs as written once the domain is verified.
Can I send email with Python without SMTP?
Yes. This is plain HTTPS, so Python needs no mail library and no SMTP port - which matters on hosts that block outbound 25 and 587. Failures come back as a status code on the call instead of as a bounce message hours later.
More guides
Send email with Django
Send transactional email from a Django view or task over the HTTP API.
Send email with Flask
Send email from a Flask route with the REST API.
Send your first email in minutes
6,000 emails a month (up to 200 a day), free forever. No card needed.