Postal

Anymail integrates with the Postal self-hosted transactional email platform, using their HTTP email API.

Settings

EMAIL_BACKEND

To use Anymail’s Postal backend, set:

EMAIL_BACKEND = "anymail.backends.postal.EmailBackend"

in your settings.py.

POSTAL_API_KEY

Required. A Postal API key.

ANYMAIL = {
    ...
    "POSTAL_API_KEY": "<your api key>",
}

Anymail will also look for POSTAL_API_KEY at the root of the settings file if neither ANYMAIL["POSTAL_API_KEY"] nor ANYMAIL_POSTAL_API_KEY is set.

POSTAL_API_URL

Required. The base url for calling the Postal API.

POSTAL_WEBHOOK_KEY

Required when using status tracking or inbound webhooks.

This should be set to the public key of the Postal instance. You can find it by running postal default-dkim-record on your Postal instance. Use the part that comes after p=, until the semicolon at the end.

esp_extra support

To use Postal features not directly supported by Anymail, you can set a message’s esp_extra to a dict that will be merged into the json sent to Postal’s email API.

Example:

message.esp_extra = {
    'HypotheticalFuturePostalParam': '2022',  # merged into send params
}

(You can also set "esp_extra" in Anymail’s global send defaults to apply it to all messages.)

Limitations and quirks

Postal does not support a few tracking and reporting additions offered by other ESPs.

Anymail normally raises an AnymailUnsupportedFeature error when you try to send a message using features that Postal doesn’t support You can tell Anymail to suppress these errors and send the messages anyway – see Unsupported features.

Single tag

Postal allows a maximum of one tag per message. If your message has two or more tags, you’ll get an AnymailUnsupportedFeature error—or if you’ve enabled ANYMAIL_IGNORE_UNSUPPORTED_FEATURES, Anymail will use only the first tag.

No delayed sending

Postal does not support send_at.

Toggle click-tracking and open-tracking

By default, Postal does not enable click-tracking and open-tracking. To enable it, see their docs on click- & open-tracking. Anymail’s track_clicks and track_opens settings are unsupported.

Attachments must be named

Postal issues an AttachmentMissingName error when trying to send an attachment without name.

No merge features

Because Postal does not support batch sending, Anymail’s merge_headers, merge_metadata, and merge_data are not supported.

Batch sending/merge and ESP templates

Postal does not support batch sending or ESP templates.

Status tracking webhooks

If you are using Anymail’s normalized status tracking, set up a webhook in your Postal mail server settings, under Webhooks. The webhook URL is:

https://yoursite.example.com/anymail/postal/tracking/

  • yoursite.example.com is your Django site

Choose all the event types you want to receive.

Postal signs its webhook payloads. You need to set ANYMAIL_POSTAL_WEBHOOK_KEY.

If you use multiple Postal mail servers, you’ll need to repeat entering the webhook settings for each of them.

Postal will report these Anymail event_types: failed, bounced, deferred, queued, delivered, clicked.

The event’s esp_event field will be a dict of Postal’s webhook data.

Inbound webhook

If you want to receive email from Postal through Anymail’s normalized inbound handling, follow Postal’s guide to for receiving emails (Help > Receiving Emails) to create an incoming route. Then set up an HTTP Endpoint, pointing to Anymail’s inbound webhook.

The url will be:

https://yoursite.example.com/anymail/postal/inbound/

  • yoursite.example.com is your Django site

Set Format to Delivered as the raw message.

You also need to set ANYMAIL_POSTAL_WEBHOOK_KEY to enable signature validation.