Feature: Add envelope_sender

New EmailMessage attribute `envelope_sender` controls ESP's sender,
sending domain, or return path where supported:

* Mailgun: overrides SENDER_DOMAIN on individual message
  (domain portion only)
* Mailjet: becomes `Sender` API param
* Mandrill: becomes `return_path_domain` API param
  (domain portion only)
* SparkPost: becomes `return_path` API param
* Other ESPs: not believed to be supported

Also support undocumented Django SMTP backend behavior, where envelope
sender is given by `message.from_email` when
`message.extra_headers["From"]` is set. Fixes #91.
This commit is contained in:
medmunds
2018-02-26 18:42:19 -08:00
parent bd9d92f5a0
commit 07fbeac6bd
27 changed files with 246 additions and 28 deletions

View File

@@ -28,32 +28,33 @@ The table below summarizes the Anymail features supported for each ESP.
.. currentmodule:: anymail.message
============================================ ========== ========== ========== ========== ========== ============ ===========
Email Service Provider |Mailgun| |Mailjet| |Mandrill| |Postmark| |SendGrid| |SendinBlue| |SparkPost|
============================================ ========== ========== ========== ========== ========== ============ ===========
============================================ =========== ========== =========== ========== ========== ============ ===========
Email Service Provider |Mailgun| |Mailjet| |Mandrill| |Postmark| |SendGrid| |SendinBlue| |SparkPost|
============================================ =========== ========== =========== ========== ========== ============ ===========
.. rubric:: :ref:`Anymail send options <anymail-send-options>`
-----------------------------------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.metadata` Yes Yes Yes No Yes Yes Yes
:attr:`~AnymailMessage.send_at` Yes No Yes No Yes No Yes
:attr:`~AnymailMessage.tags` Yes Max 1 tag Yes Max 1 tag Yes Max 1 tag Max 1 tag
:attr:`~AnymailMessage.track_clicks` Yes Yes Yes Yes Yes No Yes
:attr:`~AnymailMessage.track_opens` Yes Yes Yes Yes Yes No Yes
-------------------------------------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.envelope_sender` Domain only Yes Domain only No No No Yes
:attr:`~AnymailMessage.metadata` Yes Yes Yes No Yes Yes Yes
:attr:`~AnymailMessage.send_at` Yes No Yes No Yes No Yes
:attr:`~AnymailMessage.tags` Yes Max 1 tag Yes Max 1 tag Yes Max 1 tag Max 1 tag
:attr:`~AnymailMessage.track_clicks` Yes Yes Yes Yes Yes No Yes
:attr:`~AnymailMessage.track_opens` Yes Yes Yes Yes Yes No Yes
.. rubric:: :ref:`templates-and-merge`
-----------------------------------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.template_id` No Yes Yes Yes Yes Yes Yes
:attr:`~AnymailMessage.merge_data` Yes Yes Yes No Yes No Yes
:attr:`~AnymailMessage.merge_global_data` (emulated) Yes Yes Yes Yes Yes Yes
-------------------------------------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.template_id` No Yes Yes Yes Yes Yes Yes
:attr:`~AnymailMessage.merge_data` Yes Yes Yes No Yes No Yes
:attr:`~AnymailMessage.merge_global_data` (emulated) Yes Yes Yes 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
|AnymailTrackingEvent| from webhooks Yes Yes Yes Yes Yes No Yes
-------------------------------------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.anymail_status` Yes Yes Yes Yes Yes Yes Yes
|AnymailTrackingEvent| from webhooks Yes Yes Yes Yes Yes No Yes
.. rubric:: :ref:`Inbound handling <inbound>`
-----------------------------------------------------------------------------------------------------------------------------------
|AnymailInboundEvent| from webhooks Yes Yes Yes Yes Yes No Yes
============================================ ========== ========== ========== ========== ========== ============ ===========
-------------------------------------------------------------------------------------------------------------------------------------
|AnymailInboundEvent| from webhooks Yes Yes Yes Yes Yes No Yes
============================================ =========== ========== =========== ========== ========== ============ ===========
Trying to choose an ESP? Please **don't** start with this table. It's far more

View File

@@ -94,15 +94,22 @@ Mailgun account is configured for "*mail1*.example.com", you should provide
If you need to override the sender domain for an individual message,
include `sender_domain` in Anymail's :attr:`~anymail.message.AnymailMessage.esp_extra`
for that message:
use Anymail's :attr:`~anymail.message.AnymailMessage.envelope_sender`
(only the domain is used; anything before the @ is ignored):
.. code-block:: python
message = EmailMessage(from_email="marketing@example.com", ...)
message.esp_extra = {"sender_domain": "mail2.example.com"}
message.envelope_sender = "anything@mail2.example.com" # the "anything@" is ignored
.. versionchanged:: 2.0
Earlier Anymail versions looked for a special `sender_domain` key in the message's
:attr:`~anymail.message.AnymailMessage.esp_extra` to override Mailgun's sender domain.
This is still supported, but may be deprecated in a future release. Using
:attr:`~anymail.message.AnymailMessage.envelope_sender` as shown above is now preferred.
.. _Mailgun sender domain:
https://help.mailgun.com/hc/en-us/articles/202256730-How-do-I-pick-a-domain-name-for-my-Mailgun-account-
@@ -139,6 +146,12 @@ Limitations and quirks
if you need to access that metadata from an opened, clicked, or unsubscribed
:ref:`tracking event <event-tracking>` handler.
**Envelope sender uses only domain**
Anymail's :attr:`~anymail.message.AnymailMessage.envelope_sender` is used to
select your Mailgun :ref:`sender domain <mailgun-sender-domain>`. For
obvious reasons, only the domain portion applies. You can use anything before
the @, and it will be ignored.
.. _mailgun-templates:

View File

@@ -126,6 +126,11 @@ Limitations and quirks
**No delayed sending**
Mailjet does not support :attr:`~anymail.message.AnymailMessage.send_at`.
**Envelope sender may require approval**
Anymail passes :attr:`~anymail.message.AnymailMessage.envelope_sender` to
Mailjet, but this may result in an API error if you have not received
special approval from Mailjet support to use custom senders.
**Commas in recipient names**
Mailjet's v3 API does not properly handle commas in recipient display-names
*if* your message also uses the ``cc`` or ``bcc`` fields.

View File

@@ -129,6 +129,18 @@ as Mandrill's more complex list of name/content dicts.
.. _messages/send API:
https://mandrillapp.com/api/docs/messages.JSON.html#method=send
.. _mandrill-quirks:
Limitations and quirks
----------------------
**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.
(Mandrill always generates its own encoded mailbox for the envelope sender.)
.. _mandrill-templates:
Batch sending/merge and ESP templates
@@ -363,6 +375,13 @@ Changes to EmailMessage attributes
With Anymail, set ``message.from_email = None`` or ``message.subject = None``
to use the values from the stored template.
``message.return_path_domain``
With Anymail, set :attr:`~anymail.message.AnymailMessage.envelope_sender`
instead. You'll need to pass a valid email address (not just a domain),
but Anymail will use only the domain, and will ignore anything before the @.
.. versionchanged:: 2.0
**Other Mandrill-specific attributes**
Djrill allowed nearly all Mandrill API parameters to be set
as attributes directly on an EmailMessage. With Anymail, you

View File

@@ -120,6 +120,11 @@ see :ref:`unsupported-features`.
.. _several link-tracking options:
http://developer.postmarkapp.com/developer-link-tracking.html
**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:

View File

@@ -195,6 +195,10 @@ Limitations and quirks
(Tested March, 2016)
**No envelope sender overrides**
SendGrid does not support overriding :attr:`~anymail.message.AnymailMessage.envelope_sender`
on individual messages.
.. _sendgrid-templates:

View File

@@ -1,7 +1,7 @@
.. _sendinblue-backend:
SendinBlue
========
==========
Anymail integrates with the `SendinBlue`_ email service, using their `Web API v3`_.
@@ -88,3 +88,7 @@ Limitations and quirks
If you use a template you will suffer some limitations:
you can't change the subject or/and the body, and all email's
display-names will be hidden.
**No envelope sender overrides**
SendinBlue does not support overriding :attr:`~anymail.message.AnymailMessage.envelope_sender`
on individual messages.

View File

@@ -127,6 +127,13 @@ Limitations and quirks
(SparkPost's "recipient tags" are not available for tagging *messages*.
They're associated with individual *addresses* in stored recipient lists.)
**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
email address, but depending on your SparkPost configuration, SparkPost may
use only the domain portion and substitute its own encoded mailbox before
the @.
.. _sparkpost-templates: