Skip to main content

django-listmonk-mailer

A Django email backend that sends mail through listmonk's transactional API, built for Django 6.1's MAILERS setting.

Once it is configured, send_mail(), EmailMessage.send(), mail_admins(), password-reset emails and everything else in Django that sends email go out through listmonk.

Requirements

  • Python 3.12+
  • Django 6.1+
  • A listmonk instance with an API user and a transactional template

Installation

pip install django-listmonk-mailer

Setup

1. Create an API user in listmonk

In listmonk, go to Admin → Users, create an API user and copy its token. Give it a role that is allowed to send transactional messages (tx:send).

2. Create a transactional template

Go to Campaigns → Templates → New, choose the Transactional type and use this as the body:

{{ if .Tx.Data.html }}{{ Safe .Tx.Data.html }}{{ else }}{{ Safe .Tx.Data.body }}{{ end }}

Set the template's subject to {{ .Tx.Data.subject }} (the backend also sends the subject as an override, so this is only a fallback). Note the template's ID.

The backend sends this in the template's .Tx.Data:

Key Contents
subject The message subject
body The plain-text body (empty for HTML-only messages)
html The HTML body or text/html alternative (empty if none)

plus anything from the data option and per-message data (see below). You can also build a fully designed template that uses only your own data keys.

3. Configure MAILERS

# settings.py
MAILERS = {
    "default": {
        "BACKEND": "django_listmonk_mailer.EmailBackend",
        "OPTIONS": {
            "url": "https://listmonk.example.com",
            "username": "django-api",
            "token": env("LISTMONK_TOKEN"),
            "template_id": 3,
        },
    },
}

Then send mail as usual:

from django.core import mail

mail.send_mail("Welcome!", "Thanks for signing up.", None, ["jane@example.com"])

Options

Option Default Description
url required Base URL of your listmonk instance.
username required listmonk API user name.
token required listmonk API user token.
template_id required ID of the transactional template to render messages with.
subscriber_mode "external" "external" sends to any address without looking it up; "fallback" uses subscriber data when the address is a subscriber and sends anyway when it isn't; "default" only sends to existing subscribers. None omits the field, for listmonk versions that do not support it.
messenger None listmonk messenger to send through (listmonk defaults to email).
content_type None "html", "markdown" or "plain". By default it is "html" when the message has an HTML body and "plain" otherwise.
data {} Extra values added to .Tx.Data on every message, e.g. {"site_name": "Example"}.
timeout 10.0 HTTP timeout in seconds.
verify True TLS verification, passed to httpx.
fail_silently False Ignore listmonk and network errors instead of raising them.

Multiple configurations

Use named mailers for different templates or listmonk instances, and select one with using:

MAILERS = {
    "default": {
        "BACKEND": "django_listmonk_mailer.EmailBackend",
        "OPTIONS": {**LISTMONK, "template_id": 3},
    },
    "receipts": {
        "BACKEND": "django_listmonk_mailer.EmailBackend",
        "OPTIONS": {**LISTMONK, "template_id": 8},
    },
    # Error emails that should never raise.
    "admin-logging": {
        "BACKEND": "django_listmonk_mailer.EmailBackend",
        "OPTIONS": {**LISTMONK, "template_id": 3, "fail_silently": True},
    },
}

mail.send_mail("Your receipt", body, None, [user.email], using="receipts")

Per-message options

Set a listmonk dict on a message to override any field of the /api/tx request for that message. data is merged into the default .Tx.Data rather than replacing it:

from django.core.mail import EmailMessage

message = EmailMessage("Order shipped", "Your order is on its way.", to=[user.email])
message.listmonk = {
    "template_id": 12,
    "data": {"order_id": order.pk, "tracking_url": order.tracking_url},
}
message.send()

How messages are mapped

  • Recipients: to, cc and bcc addresses are combined and deduplicated into subscriber_emails. listmonk sends each recipient their own copy, so recipients never see each other's addresses and there is no Cc header.
  • From: from_email (or DEFAULT_FROM_EMAIL) is sent as from_email.
  • Bodies: an HTML alternative (attach_alternative(..., "text/html")) or an HTML body (content_subtype = "html") is sent as .Tx.Data.html. When a message has both plain text and HTML, the plain text is also sent as altbody for a multipart email.
  • Headers: reply_to and extra_headers are sent as headers. From, To, Cc, Bcc and Subject headers are dropped, because listmonk sets those.
  • Attachments: sent as multipart/form-data file uploads.

Errors

Failures raise django_listmonk_mailer.ListmonkError, which has status_code, response and email_message attributes. It subclasses OSError, like smtplib.SMTPException, so the recommended pattern of catching OSError for delivery problems works unchanged:

try:
    mail.send_mail(...)
except OSError:
    logger.warning("Could not send email", exc_info=True)

Invalid OPTIONS raise django.core.mail.InvalidMailer when the mailer is first used.

Development

python -m venv .venv
.venv/bin/pip install -e ".[test]"
.venv/bin/pytest

License

MIT

Metadata

Release files for django-listmonk-mailer 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-listmonk-mailer 0.1.0
File Size Uploaded Provenance
django_listmonk_mailer-0.1.0.tar.gz 9.6 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for django-listmonk-mailer 0.1.0
File Interpreter ABI Platform
django_listmonk_mailer-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 18.1 kB

Release files / django_listmonk_mailer-0.1.0.tar.gz

Download URL django_listmonk_mailer-0.1.0.tar.gz
Size 9.6 kB
Tags Source
SHA-256 checksum
How to use checksums
b31a554ce559725121f1cdef8558e61305daf575ef439d8a70dea78df398128b
BLAKE2b-256 checksum
How to use checksums
aca4bbbfcc9bff45f54bf47e7166e145d1837771248a1487850272c50daee825
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / django_listmonk_mailer-0.1.0-py3-none-any.whl

Download URL django_listmonk_mailer-0.1.0-py3-none-any.whl
Size 8.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
11db73ce2ca2b056f775044a982d8ac1f9d0c086317ae02fe27907c68e1a4fa8
BLAKE2b-256 checksum
How to use checksums
a17e0cd280e87dbeab7466f6bc861e882f008f1ec6f9d47426fc9493eef4a2a9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Security for django-listmonk-mailer 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for django_listmonk_mailer-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page