Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MailKite FastAPI starter

A runnable FastAPI app that sends email through MailKite's API — an HTML form for a quick visual test, plus a JSON endpoint for curl or another service.

There's no swappable "mailer" concept in FastAPI itself (unlike Django's EMAIL_BACKEND or Laravel's Mail::extend) — apps that need email just call an SDK or an SMTP library directly. This starter shows the idiomatic way to do that: call the MailKite Python SDK, and keep the (synchronous) SDK call from blocking FastAPI's async event loop. See mailkite_client.py for how, and the integration docs for why.

Setup

python -m venv .venv && source .venv/bin/activate   # optional but recommended
pip install -r requirements.txt
cp .env.example .env    # then edit .env with your real key

Required environment variables:

Variable Required Description
MAILKITE_API_KEY yes Your MailKite API key (mk_live_…) — dashboard → Settings → API key, or a domain-scoped key per app/tenant.
MAILKITE_FROM no Prefills the "From" field on the form. Must be an address on a domain you've verified with MailKite.

Load .env however your shell does (export $(cat .env | xargs), direnv, python-dotenv, ...) — this starter doesn't hard-code a .env loader so it stays dependency-minimal; add python-dotenv if you want it auto-loaded.

Run

export MAILKITE_API_KEY=mk_live_your_key_here
uvicorn main:app --reload

Open http://127.0.0.1:8000/ — fill in the form and send a real email.

Or hit the JSON endpoint directly:

curl -s -X POST http://127.0.0.1:8000/api/send \
  -H "Content-Type: application/json" \
  -d '{"to":"ada@example.com","subject":"Hi from FastAPI","html":"<p>Hello!</p>"}'

Interactive API docs (Swagger UI) are at http://127.0.0.1:8000/docs.

What's in here

File What it does
main.py The FastAPI app: GET / (form), POST /send (form handler), POST /api/send (JSON).
mailkite_client.py Wraps the sync MailKite SDK in run_in_threadpool so sends don't block the event loop.
templates/index.html The send-mail form (Jinja2).
static/style.css Minimal, theme-aware styling — no build step, no frontend framework.
requirements.txt fastapi, uvicorn, jinja2, python-multipart, mailkite-dev.

Why not async def calling the SDK directly?

mailkite-dev (the official Python SDK) is intentionally zero-dependency and synchronous — it uses urllib.request under the hood, not httpx/aiohttp. Calling mk.send(...) inside an async def path operation would block the whole event loop for the length of that HTTP round trip, stalling every other concurrent request on that worker. mailkite_client.send_email() wraps the call in FastAPI/Starlette's run_in_threadpool instead, so the blocking I/O runs on a worker thread. (A plain def path operation gets this for free — FastAPI runs sync route handlers in a threadpool automatically — but the explicit wrap here keeps the route async def and makes the tradeoff visible rather than relying on that implicit behavior.)

For fire-and-forget sends (e.g. a signup confirmation you don't want the response to wait on), use BackgroundTasks instead:

from fastapi import BackgroundTasks

@app.post("/signup")
async def signup(background_tasks: BackgroundTasks, ...):
    create_user(...)
    background_tasks.add_task(get_client().send, {...})  # fire-and-forget
    return {"ok": True}

SMTP relay alternative

MailKite also speaks SMTP (smtp.mailkite.dev:587, STARTTLS, your API key as the password) — see the SMTP relay docs. That's a good fit if you're already using fastapi-mail / fastapi-mailman (both wrap aiosmtplib) and don't want to touch your send call sites; this starter uses the API path instead because it gets you templates, batch sends, scheduled sends, and inbound webhooks that plain SMTP can't express.

Docs

Full write-up: https://mailkite.dev/docs/integrations/fastapi

About

Runnable FastAPI starter demonstrating MailKite via the Python SDK

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages