Python Quickstart
Send your first email from a Python project. Works with any Python 3.8+ runtime — Django, Flask, FastAPI, scripts, Lambda. The SDK is pure-Python, no compiled deps.
1. Install
terminal
pip install mailstorm # or with uv: uv pip install mailstorm # or in pyproject.toml: dependencies = ["mailstorm"]
2. Get an API key
Sign up at mailstorm.dev. Generate a key at /api-keys.
ms_test_*— sandbox; captures without sending. Great for tests.ms_live_*— production. Requires a verified FROM domain.
3. Send your first email
send.py
import os from mailstorm import Mailstorm ms = Mailstorm(os.environ["MAILSTORM_API_KEY"]) resp = ms.emails.send( from_="onboarding@yourdomain.com", to="user@example.com", subject="Hello", html="<p>It works.</p>", ) print("sent:", resp["id"])
Note on from_: Python reserves from as a keyword. The SDK accepts from_ as the parameter name and serializes it to the wire as from.
4. Verify your sending domain
Live sends require ownership of the FROM domain. Add your domain at /domains; paste the DKIM, SPF, DMARC records into your DNS host. Verification typically completes in 5 minutes after propagation.
5. Send to multiple recipients
python
ms.emails.send( from_="alerts@yourdomain.com", to=["a@example.com", "b@example.com"], cc=["c@example.com"], reply_to="support@yourdomain.com", subject="System update", html="<p>...</p>", )
6. Send a batch
python
ms.batch.send([ {"from": "alerts@yourdomain.com", "to": "a@example.com", "subject": "x", "html": "<p>1</p>"}, {"from": "alerts@yourdomain.com", "to": "b@example.com", "subject": "y", "html": "<p>2</p>"}, ])
7. Idempotency
python
ms.emails.send( from_="...", to="...", subject="Order confirmation", html="<p>...</p>", idempotency_key="order-12345", )
8. Common patterns
Django
settings.py
MAILSTORM_API_KEY = os.environ["MAILSTORM_API_KEY"]signals.py
from django.dispatch import receiver from django.contrib.auth.signals import user_logged_in from mailstorm import Mailstorm @receiver(user_logged_in) def welcome(sender, user, request, **kwargs): Mailstorm(settings.MAILSTORM_API_KEY).emails.send( from_="hi@yourdomain.com", to=user.email, subject="Welcome", html=render_to_string("emails/welcome.html", {"user": user}), )
FastAPI
main.py
from fastapi import BackgroundTasks, FastAPI from mailstorm import Mailstorm ms = Mailstorm(os.environ["MAILSTORM_API_KEY"]) app = FastAPI() def _send_welcome(email: str): ms.emails.send(from_="hi@yourdomain.com", to=email, subject="Welcome", html="...") @app.post("/signup") def signup(email: str, bg: BackgroundTasks): bg.add_task(_send_welcome, email) return {"ok": True}
What's next
- Webhooks — listen for delivered/bounced/opened/clicked/inbound
- API Reference — every endpoint with try-it-out
- Migrate from Resend — if you're coming from
resendon PyPI