mailkube-django
Django email backend for mailkube.
Which backend?
Two backends ship in one distribution. Pick one with EMAIL_BACKEND.
backends.EmailBackend |
anymail_backend.EmailBackend |
|
|---|---|---|
| Extra dependencies | none beyond Django + the SDK | django-anymail |
send_mail, EmailMessage, EmailMultiAlternatives |
yes | yes |
| Attachments, cc/bcc, reply-to, custom headers | yes | yes |
Tags, scheduled send, templates, esp_extra |
yes | |
pre_send / post_send signals, anymail_status |
yes | |
| Portable across ESPs | yes |
Choose the standalone backend if you just want Django mail to go through mailkube. Choose the Anymail one if you already use Anymail, want its extra message features, or want to keep the option of swapping providers.
Both send through the same SDK, so the wire behaviour is identical.
Install
pip install mailkube-django
# or, for the Anymail backend:
pip install "mailkube-django[anymail]"
Standalone backend
# settings.py
EMAIL_BACKEND = "mailkube_django.backends.EmailBackend"
MAILKUBE_API_KEY = "mk_..." # or the MAILKUBE_API_KEY env var
DEFAULT_FROM_EMAIL = "Acme <hello@yourdomain.com>"
from django.core.mail import send_mail
send_mail("Hello world", "It works!", None, ["customer@example.com"])
Optional settings: MAILKUBE_BASE_URL and MAILKUBE_TIMEOUT. Anything left unset falls
through to the SDK, which reads MAILKUBE_API_KEY / MAILKUBE_BASE_URL from the environment.
Anymail backend
# settings.py
EMAIL_BACKEND = "mailkube_django.anymail_backend.EmailBackend"
ANYMAIL = {"MAILKUBE_API_KEY": "mk_..."}
from django.core.mail import EmailMultiAlternatives
message = EmailMultiAlternatives("Hello", "It works!", None, ["customer@example.com"])
message.attach_alternative("<p>It works!</p>", "text/html")
message.tags = ["welcome"]
message.send()
message.anymail_status.recipients["customer@example.com"].message_id
Supported Anymail features: tags, send_at, template_id, merge_global_data,
esp_extra, the send signals, and per-recipient anymail_status. Features the API has no
equivalent for (such as metadata and per-recipient merge_data) raise Anymail's usual
unsupported-feature error rather than being silently dropped.
Webhooks
# urls.py
from mailkube_django.webhooks import WebhookView
urlpatterns = [path("webhooks/mailkube/", WebhookView.as_view())]
# settings.py
MAILKUBE_WEBHOOK_SECRET = "whsec_..."
from django.dispatch import receiver
from mailkube import EmailSentEvent
from mailkube_django.webhooks import webhook_received
@receiver(webhook_received)
def handle(sender, event, **kwargs):
if isinstance(event, EmailSentEvent):
print(event.data.email_id, event.data.sent.recipient)
Signatures are verified by the SDK over the raw request body before the signal fires, and
event is one of the SDK's typed WebhookEvent models. An event type your installed SDK
version does not know arrives as UnknownEvent with its raw data intact, so a new
platform event never breaks a receiver. A delivery whose signature does not check out, or
whose body is not a readable event, gets a 400 and no signal.
Checks
Add "mailkube_django" to INSTALLED_APPS (optional) to have manage.py check warn
about a missing API key or a selected Anymail backend without the extra installed. Sending
works either way; the app registers nothing but those checks, and there are no models or
migrations.
Contributing
See CONTRIBUTING.md for the development setup and the quality gates every change
must pass. Conventions live in .rules/, indexed by AGENTS.md. Security
issues: see SECURITY.md.
License
Apache-2.0 © 2026 Mailtactic, Corp.
Release files for mailkube-django 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mailkube_django-1.1.0.tar.gz | 17.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mailkube_django-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 38.3 kB
Release files / mailkube_django-1.1.0.tar.gz
| Download URL | mailkube_django-1.1.0.tar.gz |
|---|---|
| Size | 17.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1948527c2dd523f1439c05965d7f96263872031316636d2e034178c2e90dac9d
|
|
BLAKE2b-256 checksum How to use checksums |
224b803d343d6805c1235afc0f9576aa4002ca20935a6f46f00c89c397cd2149
|
| 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 Aug 19, 2026.
Transparency logRelease files / mailkube_django-1.1.0-py3-none-any.whl
| Download URL | mailkube_django-1.1.0-py3-none-any.whl |
|---|---|
| Size | 20.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9c2b780658b95116fe730c7455fef1b365bc3642bed022783b8bd572ed32ca12
|
|
BLAKE2b-256 checksum How to use checksums |
bc417d207a1004ba382672a3fa13708f8e2e9cc49c30d02b09499e67d10f354d
|
| 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 Aug 19, 2026.
Transparency log