mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 11:51:05 -05:00
For ESPs that have incorporated new owners in their branding, identify the new owner in the docs: - Mailgun -> Sinch Mailgun - Postmark -> ActiveCampaign Postmark - SendGrid -> Twilio SendGrid - SparkPost -> Bird ??? (Bird's rebranding of SparkPost seems to still be a work in progress at this point. In fact, Bird's rebranding of itself from MessageBird seems incomplete.) There are no current plans to rename ESP backends, as the new owners seem to be mostly keeping the original ESP names and domains for API endpoints, docs, etc. (Similarly, I'm not updating project keywords.)
278 lines
9.9 KiB
ReStructuredText
278 lines
9.9 KiB
ReStructuredText
.. _postmark-backend:
|
|
|
|
Postmark
|
|
========
|
|
|
|
Anymail integrates with the ActiveCampaign `Postmark`_ transactional email service,
|
|
using their `HTTP email API`_.
|
|
|
|
.. sidebar:: Alternatives
|
|
|
|
The :pypi:`postmarker` package includes a `Postmarker Django EmailBackend`_.
|
|
Depending on your needs, it may be more appropriate than Anymail.
|
|
|
|
.. _Postmark: https://postmarkapp.com/
|
|
.. _HTTP email API: https://postmarkapp.com/developer/api/email-api
|
|
.. _Postmarker Django EmailBackend:
|
|
https://postmarker.readthedocs.io/en/stable/django.html
|
|
|
|
Settings
|
|
--------
|
|
|
|
.. rubric:: EMAIL_BACKEND
|
|
|
|
To use Anymail's Postmark backend, set:
|
|
|
|
.. code-block:: python
|
|
|
|
EMAIL_BACKEND = "anymail.backends.postmark.EmailBackend"
|
|
|
|
in your settings.py.
|
|
|
|
|
|
.. setting:: ANYMAIL_POSTMARK_SERVER_TOKEN
|
|
|
|
.. rubric:: POSTMARK_SERVER_TOKEN
|
|
|
|
Required. A Postmark server token.
|
|
|
|
.. code-block:: python
|
|
|
|
ANYMAIL = {
|
|
...
|
|
"POSTMARK_SERVER_TOKEN": "<your server token>",
|
|
}
|
|
|
|
Anymail will also look for ``POSTMARK_SERVER_TOKEN`` at the
|
|
root of the settings file if neither ``ANYMAIL["POSTMARK_SERVER_TOKEN"]``
|
|
nor ``ANYMAIL_POSTMARK_SERVER_TOKEN`` is set.
|
|
|
|
You can override the server token for an individual message in
|
|
its :ref:`esp_extra <postmark-esp-extra>`.
|
|
|
|
|
|
.. setting:: ANYMAIL_POSTMARK_API_URL
|
|
|
|
.. rubric:: POSTMARK_API_URL
|
|
|
|
The base url for calling the Postmark API.
|
|
|
|
The default is ``POSTMARK_API_URL = "https://api.postmarkapp.com/"``
|
|
(It's unlikely you would need to change this.)
|
|
|
|
|
|
.. _postmark-esp-extra:
|
|
|
|
esp_extra support
|
|
-----------------
|
|
|
|
To use Postmark features not directly supported by Anymail, you can
|
|
set a message's :attr:`~anymail.message.AnymailMessage.esp_extra` to
|
|
a `dict` that will be merged into the json sent to Postmark's
|
|
`email API`_.
|
|
|
|
Example:
|
|
|
|
.. code-block:: python
|
|
|
|
message.esp_extra = {
|
|
'MessageStream': 'marketing', # send using specific message stream ID
|
|
'server_token': '<API server token for just this message>',
|
|
}
|
|
|
|
|
|
(You can also set `"esp_extra"` in Anymail's
|
|
:ref:`global send defaults <send-defaults>` to apply it to all
|
|
messages.)
|
|
|
|
|
|
.. _email API: https://postmarkapp.com/developer/api/email-api
|
|
|
|
|
|
Limitations and quirks
|
|
----------------------
|
|
|
|
Postmark does not support a few tracking and reporting additions offered by other ESPs.
|
|
|
|
Anymail normally raises an :exc:`~anymail.exceptions.AnymailUnsupportedFeature`
|
|
error when you try to send a message using features that Postmark doesn't support
|
|
You can tell Anymail to suppress these errors and send the messages anyway --
|
|
see :ref:`unsupported-features`.
|
|
|
|
**Single tag**
|
|
Postmark allows a maximum of one tag per message. If your message has two or more
|
|
:attr:`~anymail.message.AnymailMessage.tags`, you'll get an
|
|
:exc:`~anymail.exceptions.AnymailUnsupportedFeature` error---or
|
|
if you've enabled :setting:`ANYMAIL_IGNORE_UNSUPPORTED_FEATURES`,
|
|
Anymail will use only the first tag.
|
|
|
|
**No delayed sending**
|
|
Postmark does not support :attr:`~anymail.message.AnymailMessage.send_at`.
|
|
|
|
**Click-tracking**
|
|
Postmark supports `several link-tracking options`_. Anymail treats
|
|
:attr:`~anymail.message.AnymailMessage.track_clicks` as Postmark's
|
|
"HtmlAndText" option when True.
|
|
|
|
If you would prefer Postmark's "HtmlOnly" or "TextOnly" link-tracking, you could
|
|
either set that as a Postmark server-level default (and use `message.track_clicks = False`
|
|
to disable tracking for specific messages), or use something like
|
|
`message.esp_extra = {'TrackLinks': "HtmlOnly"}` to specify a particular option.
|
|
|
|
.. _several link-tracking options:
|
|
https://postmarkapp.com/developer/user-guide/tracking-links#enabling-link-tracking
|
|
|
|
**Open-tracking**
|
|
To control :attr:`~anymail.message.AnymailMessage.track_opens` on individual messages,
|
|
you must *disable* Postmark's server-level default and then set ``track_opens = True``
|
|
on all messages that should have open tracking. (A message-level ``track_opens = False``
|
|
`cannot override open tracking`_ if enabled in Postmark's server defaults.)
|
|
|
|
If most of your messages should be sent with open tracking, you can use Anymail's
|
|
:ref:`global send defaults <send-defaults>` (rather than Postmark's server-level setting):
|
|
|
|
.. code-block:: python
|
|
|
|
# settings.py
|
|
ANYMAIL = {
|
|
# ...
|
|
"SEND_DEFAULTS": { "track_opens": True },
|
|
}
|
|
|
|
Individual messages *can* then use ``track_opens = False`` to override Anymail's default.
|
|
|
|
.. _cannot override open tracking:
|
|
https://postmarkapp.com/developer/user-guide/tracking-opens/tracking-opens-per-email
|
|
|
|
**No envelope sender overrides**
|
|
Postmark does not support overriding :attr:`~anymail.message.AnymailMessage.envelope_sender`
|
|
on individual messages. (You can configure custom return paths for each sending domain in
|
|
the Postmark control panel.)
|
|
|
|
|
|
.. _postmark-templates:
|
|
|
|
Batch sending/merge and ESP templates
|
|
-------------------------------------
|
|
|
|
Postmark offers both :ref:`ESP stored templates <esp-stored-templates>`
|
|
and :ref:`batch sending <batch-send>` with per-recipient merge data.
|
|
|
|
.. versionchanged:: 4.2
|
|
|
|
Added Postmark :attr:`~anymail.message.AnymailMessage.merge_data` and batch sending
|
|
support. (Earlier Anymail releases only supported
|
|
:attr:`~anymail.message.AnymailMessage.merge_global_data` with Postmark.)
|
|
|
|
To use a Postmark template, set the message's
|
|
:attr:`~anymail.message.AnymailMessage.template_id` to either the numeric Postmark
|
|
"TemplateID" or its string "TemplateAlias" (which is *not* the template's name).
|
|
You can find a template's numeric id near the top right in Postmark's template editor,
|
|
and set the alias near the top right above the name.
|
|
|
|
.. versionchanged:: 5.0
|
|
|
|
Earlier Anymail releases only allowed numeric template IDs.
|
|
|
|
Supply the Postmark "TemplateModel" variables using Anymail's normalized
|
|
:attr:`~anymail.message.AnymailMessage.merge_data` and
|
|
:attr:`~anymail.message.AnymailMessage.merge_global_data` message attributes:
|
|
|
|
.. code-block:: python
|
|
|
|
message = EmailMessage(
|
|
# (subject and body come from the template, so don't include those)
|
|
to=["alice@example.com", "Bob <bob@example.com>"]
|
|
)
|
|
message.template_id = 80801 # Postmark template id or alias
|
|
message.merge_data = {
|
|
'alice@example.com': {'name': "Alice", 'order_no': "12345"},
|
|
'bob@example.com': {'name': "Bob", 'order_no': "54321"},
|
|
}
|
|
message.merge_global_data = {
|
|
'ship_date': "May 15",
|
|
}
|
|
|
|
Postmark does not allow overriding the message's subject or body with a template.
|
|
(You can customize the subject by including variables in the template's subject.)
|
|
|
|
When you supply per-recipient :attr:`~anymail.message.AnymailMessage.merge_data`,
|
|
Anymail automatically switches to Postmark's batch send API, so that
|
|
each "to" recipient sees only their own email address. (Any cc's or bcc's will be
|
|
duplicated for *every* to-recipient.)
|
|
|
|
If you want to use batch sending with a regular message (without a template), set
|
|
merge data to an empty dict: `message.merge_data = {}`.
|
|
|
|
See this `Postmark blog post on templates`_ for more information.
|
|
|
|
.. _Postmark blog post on templates:
|
|
https://postmarkapp.com/blog/special-delivery-postmark-templates
|
|
|
|
|
|
.. _postmark-webhooks:
|
|
|
|
Status tracking webhooks
|
|
------------------------
|
|
|
|
If you are using Anymail's normalized :ref:`status tracking <event-tracking>`, set up
|
|
a webhook in your `Postmark account settings`_, under Servers > *your server name* >
|
|
Settings > Webhooks. The webhook URL is:
|
|
|
|
:samp:`https://{random}:{random}@{yoursite.example.com}/anymail/postmark/tracking/`
|
|
|
|
* *random:random* is an :setting:`ANYMAIL_WEBHOOK_SECRET` shared secret
|
|
* *yoursite.example.com* is your Django site
|
|
|
|
Choose all the event types you want to receive. Anymail doesn't care about the "include
|
|
messsage content" and "post only on first open" options; whether to use them is your choice.
|
|
|
|
If you use multiple Postmark servers, you'll need to repeat entering the webhook
|
|
settings for each of them.
|
|
|
|
Postmark will report these Anymail :attr:`~anymail.signals.AnymailTrackingEvent.event_type`\s:
|
|
rejected, failed, bounced, deferred, delivered, autoresponded, opened, clicked, complained,
|
|
unsubscribed, subscribed. (Postmark does not support sent--what it calls "processed"--events
|
|
through webhooks.)
|
|
|
|
The event's :attr:`~anymail.signals.AnymailTrackingEvent.esp_event` field will be
|
|
a `dict` of Postmark `delivery <https://postmarkapp.com/developer/webhooks/delivery-webhook>`_,
|
|
`bounce <https://postmarkapp.com/developer/webhooks/bounce-webhook>`_,
|
|
`spam-complaint <https://postmarkapp.com/developer/webhooks/spam-complaint-webhook>`_,
|
|
`open-tracking <https://postmarkapp.com/developer/webhooks/open-tracking-webhook>`_, or
|
|
`click <https://postmarkapp.com/developer/webhooks/click-webhook>`_ data.
|
|
|
|
.. _Postmark account settings: https://account.postmarkapp.com/servers
|
|
|
|
|
|
.. _postmark-inbound:
|
|
|
|
Inbound webhook
|
|
---------------
|
|
|
|
To receive email from Postmark through Anymail's normalized
|
|
:ref:`inbound <inbound>` handling, follow Postmark's guide to
|
|
`Configure an inbound server`_ that posts to Anymail's inbound webhook.
|
|
|
|
In their step 4, set the inbound webhook URL to:
|
|
|
|
:samp:`https://{random}:{random}@{yoursite.example.com}/anymail/postmark/inbound/`
|
|
|
|
* *random:random* is an :setting:`ANYMAIL_WEBHOOK_SECRET` shared secret
|
|
* *yoursite.example.com* is your Django site
|
|
|
|
We recommend enabling the "Include raw email content in JSON payload" checkbox.
|
|
Anymail's inbound handling supports either choice, but raw email is preferred
|
|
to get the most accurate representation of any received message. (If you are using
|
|
Postmark's server API, this is the ``RawEmailEnabled`` option.)
|
|
|
|
.. versionchanged:: 10.0
|
|
Added handling for Postmark's "include raw email content".
|
|
|
|
You may also want to read through the "Inbound domain forwarding" and
|
|
"Configure inbound blocking" sections of Postmark's `Inbound Processing`_ guide.
|
|
|
|
.. _Configure an inbound server:
|
|
https://postmarkapp.com/developer/user-guide/inbound/configure-an-inbound-server
|
|
.. _Inbound Processing: https://postmarkapp.com/developer/user-guide/inbound
|