Make Django email part of the product lifecycle. Not a fire-and-forget call from a view.
Queue transactional messages from Django, publish the events that drive follow-up flows, and trace both against one contact record.
✓Use it beside or instead of send_mail when product email needs lifecycle context and delivery evidence.
One request, complete trace
Request
POST /api/v1/emails
Authorization: Bearer aem_…
Idempotency-Key: welcome-8f21
{ "to": "[email protected]", "template": "welcome" }
202 Accepted
{ "id": "msg_7ca31", "status": "queued" }
[ 01 / 03 ]Integration shape
Keep Django requests fast without losing the message trail.
Use views, signals, and background tasks
Call directly when an accepted response is enough, or use Celery or django-q when local work must survive the request.
Publish product events
Publish lifecycle events from an application service after the database change succeeds, rather than hiding network work in a signal.
Verify the webhook
A csrf_exempt view reading request.body before anything parses it.
[ 02 / 03 ]Server quickstart
Queue a Django email and keep the message ID.
A stable idempotency key makes a task retry safe; the returned ID links the application action to delivery.
Use an async HTTP client when this runs inside an async framework.
response = requests.post(
"https://sendandretain.com/api/v1/emails",
headers={"Authorization": f"Bearer {os.environ['AEM_KEY']}",
"Idempotency-Key": f"welcome-{user.id}"},
json={"to": user.email, "template": "welcome"}, timeout=10,
)
response.raise_for_status()Accepted response
{ "id": "msg_7ca31", "status": "queued" }[ 03 / 03 ]Related
Keep building with Django
Questions people ask us
Connect your next Django event to a delivered email.
Queue the message from a service or task, then follow its ID through delivery.