Integration
Send emails from FastAPI with Postkit
Send transactional emails from FastAPI endpoints with async httpx. Full async support from request to delivery.
1. Set your API key
pip install httpx
# .env POSTKIT_API_KEY=pk_live_...
2. Send an email
python
# main.py
import os
import httpx
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class SendRequest(BaseModel):
to: str
name: str
@app.post("/send")
async def send_welcome(req: SendRequest):
async with httpx.AsyncClient() as client:
response = await client.post(
"https://api.postkit.eu/v1/emails",
headers={
"Authorization": f"Bearer {os.environ['POSTKIT_API_KEY']}",
"Content-Type": "application/json",
},
json={
"from": "hello@yourapp.eu",
"to": req.to,
"subject": "Welcome aboard!",
"html": f"<h1>Welcome, {req.name}!</h1>",
},
)
return response.json()3. Handle webhooks
Postkit sends delivery events (sent, delivered, bounced, opened, clicked) via HMAC-SHA256 signed webhooks following the Standard Webhooks specification.
python
# webhooks.py
import os, hashlib, hmac, base64, json
from fastapi import FastAPI, Request, HTTPException
app = FastAPI()
@app.post("/webhooks/postkit")
async def postkit_webhook(request: Request):
body = await request.body()
msg_id = request.headers.get("webhook-id", "")
timestamp = request.headers.get("webhook-timestamp", "")
signature = request.headers.get("webhook-signature", "")
secret_b64 = os.environ["POSTKIT_WEBHOOK_SECRET"].replace("whsec_", "")
secret = base64.b64decode(secret_b64)
content = f"{msg_id}.{timestamp}.{body.decode()}"
expected = base64.b64encode(
hmac.new(secret, content.encode(), hashlib.sha256).digest()
).decode()
valid = any(
hmac.compare_digest(s.replace("v1,", ""), expected)
for s in signature.split(" ")
)
if not valid:
raise HTTPException(status_code=401, detail="Invalid signature")
event = json.loads(body)
print(f"Postkit event: {event['type']}")
return {"received": True}