Skip to content

Commit

Permalink
Docs: merge_headers
Browse files Browse the repository at this point in the history
  • Loading branch information
medmunds committed Jun 20, 2024
1 parent 681569b commit 2c3e965
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 11 deletions.
8 changes: 8 additions & 0 deletions docs/esps/amazon_ses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ Limitations and quirks
**No delayed sending**
Amazon SES does not support :attr:`~anymail.message.AnymailMessage.send_at`.

**Merge features require template_id**
Anymail's :attr:`~anymail.message.AnymailMessage.merge_headers`,
:attr:`~anymail.message.AnymailMessage.merge_metadata`,
:attr:`~anymail.message.AnymailMessage.merge_data`, and
:attr:`~anymail.message.AnymailMessage.merge_global_data` are only supported
when sending :ref:`templated messages <amazon-ses-templates>`
(using Anymail's :attr:`~anymail.message.AnymailMessage.template_id`).

**No global send defaults for non-Anymail options**
With the Amazon SES backend, Anymail's :ref:`global send defaults <send-defaults>`
are only supported for Anymail's added message options (like
Expand Down
7 changes: 4 additions & 3 deletions docs/esps/esp-feature-matrix.csv
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
Email Service Provider,:ref:`amazon-ses-backend`,:ref:`brevo-backend`,:ref:`mailersend-backend`,:ref:`mailgun-backend`,:ref:`mailjet-backend`,:ref:`mandrill-backend`,:ref:`postal-backend`,:ref:`postmark-backend`,:ref:`resend-backend`,:ref:`sendgrid-backend`,:ref:`sparkpost-backend`,:ref:`unisender-go-backend`
.. rubric:: :ref:`Anymail send options <anymail-send-options>`,,,,,,,,,,,,
:attr:`~AnymailMessage.envelope_sender`,Yes,No,No,Domain only,Yes,Domain only,Yes,No,No,No,Yes,No
:attr:`~AnymailMessage.merge_headers`,Yes*,Yes,No,Yes,Yes,No,No,Yes,Yes,Yes,Yes*,Yes*
:attr:`~AnymailMessage.metadata`,Yes,Yes,No,Yes,Yes,Yes,No,Yes,Yes,Yes,Yes,Yes
:attr:`~AnymailMessage.merge_metadata`,No,Yes,No,Yes,Yes,Yes,No,Yes,Yes,Yes,Yes,Yes
:attr:`~AnymailMessage.merge_metadata`,Yes*,Yes,No,Yes,Yes,Yes,No,Yes,Yes,Yes,Yes,Yes
:attr:`~AnymailMessage.send_at`,No,Yes,Yes,Yes,No,Yes,No,No,No,Yes,Yes,Yes
:attr:`~AnymailMessage.tags`,Yes,Yes,Yes,Yes,Max 1 tag,Yes,Max 1 tag,Max 1 tag,Yes,Yes,Max 1 tag,Yes
:attr:`~AnymailMessage.track_clicks`,No,No,Yes,Yes,Yes,Yes,No,Yes,No,Yes,Yes,Yes
:attr:`~AnymailMessage.track_opens`,No,No,Yes,Yes,Yes,Yes,No,Yes,No,Yes,Yes,Yes
:ref:`amp-email`,Yes,No,No,Yes,No,No,No,No,No,Yes,Yes,Yes
.. rubric:: :ref:`templates-and-merge`,,,,,,,,,,,,
:attr:`~AnymailMessage.template_id`,Yes,Yes,Yes,Yes,Yes,Yes,No,Yes,No,Yes,Yes,Yes
:attr:`~AnymailMessage.merge_data`,Yes,Yes,Yes,Yes,Yes,Yes,No,Yes,No,Yes,Yes,Yes
:attr:`~AnymailMessage.merge_global_data`,Yes,Yes,(emulated),(emulated),Yes,Yes,No,Yes,No,Yes,Yes,Yes
:attr:`~AnymailMessage.merge_data`,Yes*,Yes,Yes,Yes,Yes,Yes,No,Yes,No,Yes,Yes,Yes
:attr:`~AnymailMessage.merge_global_data`,Yes*,Yes,(emulated),(emulated),Yes,Yes,No,Yes,No,Yes,Yes,Yes
.. rubric:: :ref:`Status <esp-send-status>` and :ref:`event tracking <event-tracking>`,,,,,,,,,,,,
:attr:`~AnymailMessage.anymail_status`,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes
:class:`~anymail.signals.AnymailTrackingEvent` from webhooks,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes
Expand Down
2 changes: 2 additions & 0 deletions docs/esps/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ The table below summarizes the Anymail features supported for each ESP.
:widths: auto
:class: sticky-left

\* See ESP detail page for limitations and clarifications

Trying to choose an ESP? Please **don't** start with this table. It's far more
important to consider things like an ESP's deliverability stats, latency, uptime,
and support for developers. The *number* of extra features an ESP offers is almost
Expand Down
4 changes: 4 additions & 0 deletions docs/esps/mailersend.rst
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ see :ref:`unsupported-features`.
Any other extra headers will raise an
:exc:`~anymail.exceptions.AnymailUnsupportedFeature` error.

**No merge headers support**
MailerSend's API does not provide a way to support Anymail's
:attr:`~anymail.message.AnymailMessage.merge_headers`.

**No metadata support**
MailerSend does not support Anymail's
:attr:`~anymail.message.AnymailMessage.metadata` or
Expand Down
21 changes: 13 additions & 8 deletions docs/esps/mailgun.rst
Original file line number Diff line number Diff line change
Expand Up @@ -247,18 +247,23 @@ Limitations and quirks
obvious reasons, only the domain portion applies. You can use anything before
the @, and it will be ignored.

**Using merge_metadata with merge_data**
**Using merge_metadata and merge_headers with merge_data**
If you use both Anymail's :attr:`~anymail.message.AnymailMessage.merge_data`
and :attr:`~anymail.message.AnymailMessage.merge_metadata` features, make sure your
merge_data keys do not start with ``v:``. (It's a good idea anyway to avoid colons
and other special characters in merge_data keys, as this isn't generally portable
to other ESPs.)
:attr:`~!anymail.message.AnymailMessage.merge_data` keys do not start with ``v:``.

Similarly, if you use Anymail's :attr:`~anymail.message.AnymailMessage.merge_headers`
together with :attr:`~anymail.message.AnymailMessage.merge_data`, make sure your
:attr:`~!anymail.message.AnymailMessage.merge_data` keys do not start with ``h:``.

(It's a good idea anyway to avoid colons and other special characters in merge data
keys, as this isn't generally portable to other ESPs.)

The same underlying Mailgun feature ("recipient-variables") is used to implement
both Anymail features. To avoid conflicts, Anymail prepends ``v:`` to recipient
variables needed for merge_metadata. (This prefix is stripped as Mailgun prepares
the message to send, so it won't be present in your Mailgun API logs or the metadata
that is sent to tracking webhooks.)
all three Anymail features. To avoid conflicts, Anymail prepends ``v:`` to recipient
variables needed for merge metadata, and ``h:`` for merge headers recipient variables.
(These prefixes are stripped as Mailgun prepares the message to send, so won't appear
in your Mailgun API logs or the metadata that is sent to tracking webhooks.)

**Additional limitations on merge_data with template_id**
If you are using Mailgun's stored handlebars templates (Anymail's
Expand Down
4 changes: 4 additions & 0 deletions docs/esps/mandrill.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ Limitations and quirks
(Verified and reported to MailChimp support 4/2022;
see `Anymail discussion #257`_ for more details.)

**No merge headers support**
Mandrill's API does not provide a way to support Anymail's
:attr:`~anymail.message.AnymailMessage.merge_headers`.

**Envelope sender uses only domain**
Anymail's :attr:`~anymail.message.AnymailMessage.envelope_sender` is used to
populate Mandrill's `'return_path_domain'`---but only the domain portion.
Expand Down
7 changes: 7 additions & 0 deletions docs/esps/postal.rst
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ see :ref:`unsupported-features`.
**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
:attr:`~anymail.message.AnymailMessage.merge_headers`,
:attr:`~anymail.message.AnymailMessage.merge_metadata`,
and :attr:`~anymail.message.AnymailMessage.merge_data`
are not supported.


.. _postal-templates:

Expand Down
9 changes: 9 additions & 0 deletions docs/esps/sparkpost.rst
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,15 @@ Limitations and quirks

.. versionadded:: 8.0

**Extra header limitations**
SparkPost's API silently ignores certain email headers (specified via
Django's :ref:`headers or extra_headers <message-headers>` or Anymail's
:attr:`~anymail.message.AnymailMessage.merge_headers`). In particular,
attempts to provide a custom :mailheader:`List-Unsubscribe` header will
not work; the message will be sent with SparkPost's own subscription
management headers. (The list of allowed custom headers does not seem
to be documented.)

**Envelope sender may use domain only**
Anymail's :attr:`~anymail.message.AnymailMessage.envelope_sender` is used to
populate SparkPost's `'return_path'` parameter. Anymail supplies the full
Expand Down
7 changes: 7 additions & 0 deletions docs/esps/unisender_go.rst
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,13 @@ Limitations and quirks
:attr:`~anymail.message.AnymailMessage.merge_data` or
:attr:`~anymail.message.AnymailMessage.merge_global_data`.

**Limited merge headers support**
Unisender Go supports per-recipient :mailheader:`List-Unsubscribe` headers
(if your account has been approved to disable their unsubscribe link),
but trying to include any other field in Anymail's
:attr:`~anymail.message.AnymailMessage.merge_headers` will raise
an :exc:`~anymail.exceptions.AnymailUnsupportedFeature` error.

**No envelope sender overrides**
Unisender Go does not support overriding a message's
:attr:`~anymail.message.AnymailMessage.envelope_sender`.
Expand Down
43 changes: 43 additions & 0 deletions docs/sending/anymail_additions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,49 @@ an :ref:`unsupported feature <unsupported-features>` error.
.. _how envelope sender relates to return path:
https://www.postmastery.com/blog/about-the-return-path-header/

.. attribute:: merge_headers

.. versionadded:: 11.0

On a message with multiple recipients, if your ESP supports it,
you can set this to a `dict` of *per-recipient* extra email headers.
Each key in the dict is a recipient email (address portion only),
and its value is a dict of header fields and values for that recipient:

.. code-block:: python
message.to = ["[email protected]", "R. Runner <[email protected]>"]
message.extra_headers = {
# Headers for all recipients
"List-Unsubscribe-Post": "List-Unsubscribe=One-Click",
}
message.merge_headers = {
# Per-recipient headers
"[email protected]": {
"List-Unsubscribe": "<https://example.com/unsubscribe/12345>",
},
"[email protected]": {
"List-Unsubscribe": "<https://example.com/unsubscribe/98765>",
},
}
When :attr:`!merge_headers` is set, Anymail will use the ESP's
:ref:`batch sending <batch-send>` option, so that each :attr:`to` recipient gets
an individual message (and doesn't see the other emails on the :attr:`to` list).

Many ESPs restrict which headers are allowed. Be sure to check Anymail's
:ref:`ESP-specific docs <supported-esps>` for your ESP.
(Also, :ref:`special handling <message-headers>` for :mailheader:`From`,
:mailheader:`To` and :mailheader:`Reply-To` headers does *not* apply
to :attr:`!merge_headers`.)

If :attr:`!merge_headers` defines a particular header for only some
recipients, the default for other recipients comes from the message's
:ref:`extra_headers <message-headers>`. If not defined there, behavior
varies by ESP: some will include the header field only for recipients
where you have provided it; other ESPs will send an empty header field
to the other recipients.

.. attribute:: metadata

If your ESP supports tracking arbitrary metadata, you can set this to
Expand Down

0 comments on commit 2c3e965

Please sign in to comment.