Skip to content

Django Backend

Greg Svoboda edited this page Aug 12, 2026 · 1 revision

Django Backend

postmark.django.EmailBackend is a drop-in EMAIL_BACKEND that sends Django's django.core.mail through the Postmark API. Requires the django extra:

pip install postmark-python[django]

Supports Django 4.2 LTS, 5.2 LTS, 6.0, and 6.1.

Quick Start

# settings.py
EMAIL_BACKEND = "postmark.django.EmailBackend"
POSTMARK_SERVER_TOKEN = "your-server-token"
from django.core.mail import send_mail

send_mail(
    subject="Hello from Postmark",
    message="Sent with postmark.django.EmailBackend.",
    from_email="sender@example.com",
    recipient_list=["receiver@example.com"],
    html_message="<p>Sent with <b>postmark.django.EmailBackend</b>.</p>",
)

Settings

Setting Default Description
POSTMARK_SERVER_TOKEN (required) Your Postmark server token. Can also be passed as server_token= to get_connection().
POSTMARK_TEST_MODE False When True, sends using Postmark's POSTMARK_API_TEST token instead — validates requests without delivering mail.
POSTMARK_TRACK_OPENS False Default TrackOpens value for every message, unless overridden per-message (see below).
POSTMARK_MESSAGE_STREAM None Default message stream, unless overridden per-message.

Tags, Metadata, and Message Stream

Postmark's tag, metadata, and message-stream fields have no equivalent on Django's EmailMessage, so use PostmarkEmailMessage / PostmarkEmailMultiAlternatives instead:

from postmark.django import PostmarkEmailMessage

PostmarkEmailMessage(
    subject="Your invitation",
    body="You're invited!",
    from_email="sender@example.com",
    to=["receiver@example.com"],
    tag="invitation",
    metadata={"user_id": "12345"},
    message_stream="outbound",
).send()

PostmarkEmailMixin is also available if you want to add these fields to your own EmailMessage subclass.

HTML bodies and attachments

Use Django's normal APIs — EmailMultiAlternatives.attach_alternative(html, "text/html") for an HTML body, and EmailMessage.attach(filename, content, mimetype) for attachments. Attachment content is base64-encoded automatically. Postmark's Email API accepts a single HTML body; any other alternative content type is dropped with a logged warning rather than raising.

Legacy email.mime.base.MIMEBase objects passed to .attach() are not supported — use the (filename, content, mimetype) form instead. This also means inline (Content-ID / cid:) images aren't currently supported through this backend, since Django only exposes a Content-ID header via that same legacy MIMEBase path. For inline images, either host the image externally and reference it by URL in your HTML body (see examples/django/send_with_external_image.py), or send directly with postmark.ServerClient / postmark.sync.ServerClient using an Attachment with content_id set.

Batching and errors

send_messages() batches messages in groups of up to 500 per Postmark API request. Postmark returns HTTP 200 even when individual recipients fail, so failures raise the same typed exceptions as the rest of the SDK (see Error Handling) — fail_silently=True swallows them and returns only the count of messages that actually sent, matching Django's BaseEmailBackend contract.

Signals

from postmark.django import pre_send, post_send, on_exception
  • pre_send — fires just before a batch is submitted. messages kwarg: the postmark.Email objects about to be sent.
  • post_send — fires just after a successful batch submission. messages / response kwargs.
  • on_exception — fires when send_messages() raises. raw_messages (the original Django messages) / exception kwargs.

Examples

Clone this wiki locally