Send email in Django with an email API
How to send transactional email from Django — requests/httpx to Notify, no SMTP backend required.
Send transactional email from Django with an HTTPS call from a view, signal handler, or Celery task. Keep the API key in settings/env — never in templates. You do not need Django’s SMTP email backend for this path.
Prerequisites
- API key — authenticate every request with the
x-api-keyheader - Verified domain — required for production sends from a custom
fromaddress - Django 4.2+ and Python 3.10+
requestsorhttpx
pip install requests
export NOTIFY_API_KEY=your_api_key_here
Settings
# settings.py
import os
NOTIFY_API_KEY = os.environ["NOTIFY_API_KEY"]
NOTIFY_FROM = os.environ.get("NOTIFY_FROM", "noreply@your-verified-domain.com")
NOTIFY_SEND_URL = "https://notify.cx/api/email/send"
Helper module
# mailer/notify.py
from django.conf import settings
import requests
class NotifyError(Exception):
pass
def send_email(*, to: str, subject: str, message: str, from_addr: str | None = None) -> dict:
response = requests.post(
settings.NOTIFY_SEND_URL,
headers={
"Content-Type": "application/json",
"x-api-key": settings.NOTIFY_API_KEY,
},
json={
"from": from_addr or settings.NOTIFY_FROM,
"to": to,
"subject": subject,
"message": message, # plain text or HTML
},
timeout=15,
)
if not response.ok:
raise NotifyError(f"{response.status_code}: {response.text}")
return response.json()
Call from a view
# accounts/views.py
from django.http import JsonResponse, HttpRequest
from django.views.decorators.http import require_POST
from mailer.notify import send_email, NotifyError
@require_POST
def send_welcome(request: HttpRequest):
email = request.POST.get("email")
if not email:
return JsonResponse({"error": "email required"}, status=400)
try:
send_email(
to=email,
subject="Welcome",
message="<h1>Welcome</h1><p>Thanks for joining.</p>",
)
except NotifyError as exc:
return JsonResponse({"error": str(exc)}, status=502)
return JsonResponse({"ok": True})
Under load, push sends to Celery (or similar) so the HTTP response does not wait on Notify. Prefer explicit calls from the signup path over broad post_save signals.
Render HTML with render_to_string('emails/welcome.html', context) and pass the result as message.