Start here
Getting started
MailingKit gives your Python application one small API for sending email. You install it, configure a provider, create one client and send. Everything else is opt-in.
Install
pip install mailingkit # console, file, memory and SMTP providers
pip install "mailingkit[resend]" # adds the Resend provider (httpx)MailingKit needs Python 3.11 or newer and runs on Linux, macOS and Windows. The core package depends only on Jinja2, so installing it never pulls in a web framework, a queue or a tracing library.
Send your first email
Create one client and send. With nothing configured, MailingKit uses the console provider, so this prints the email instead of sending it:
import asyncio
from mailingkit import MailingKit
async def main():
mail = MailingKit.from_env(default_sender="no-reply@example.com")
result = await mail.send(
to="ada@example.com",
subject="Your export is ready",
html="<p>Hi Ada, your export is ready to <a href='https://example.com/x'>download</a>.</p>",
)
print(result.id, result.provider)
asyncio.run(main())
A plain text part is generated from the HTML automatically, because a text alternative
improves deliverability. Pass text= yourself if you want to control it.
Configure a real provider
When you are ready to deliver for real, set environment variables. No code changes:
MAILINGKIT_PROVIDER=smtp
MAILINGKIT_FROM_EMAIL=no-reply@example.com
MAILINGKIT_FROM_NAME="Example App"
MAILINGKIT_SMTP_HOST=smtp.example.com
MAILINGKIT_SMTP_USERNAME=apikey
MAILINGKIT_SMTP_PASSWORD=change-me
MailingKit.from_env() reads them, picks the provider and sets the default sender.
Keyword arguments still win, so MailingKit.from_env(hooks=[...]) adds to what the
environment says. See Configuration for every variable.
Not async?
Use SyncMailingKit. It has the same methods and arguments, blocks until the send
finishes, and is safe to call from any thread, including Django views and Celery tasks.
The whole API
Most applications use four methods:
| Method | What it does |
|---|---|
send(to=, subject=, html=, text=, ...) | Send a message you wrote in code. |
send_template(template, data, to=, ...) | Render a template with data and send it. |
render(template, data) | Render without sending, for previews and tests. |
validate(message) | Return the exact message the provider would receive, or raise. |
Every send returns a SendResult with MailingKit's own id, the
provider name, the provider_message_id and the number of
attempts. Every failure raises a subclass of MailingKitError.