Sendinblue: rename to Brevo

* Update docs to (usually) refer to Brevo rather than Sendinblue
* Change SENDINBLUE_API_URL to api.brevo.com
   (same API is available on both domains)
* Leave code references (settings, backend name, webhook urls)
   unchanged as `sendinblue`, to avoid unnecessary client changes
This commit is contained in:
sblondon
2023-06-13 22:04:52 +02:00
committed by GitHub
parent 099ef314e4
commit 8a72f89e8a
8 changed files with 140 additions and 110 deletions

View File

@@ -25,6 +25,20 @@ Release history
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
.. This extra heading level keeps the ToC from becoming unmanageably long .. This extra heading level keeps the ToC from becoming unmanageably long
vNext
-----
*Unreleased changes*
Other
~~~~~
* **Brevo (Sendinblue):** Sendinblue has rebranded to "Brevo." Change default
API endpoint to ``api.brevo.com``, and update docs to reflect new name. Anymail
still uses ``sendinblue`` in the backend name, for settings, etc., so there
should be no impact on your code. (Thanks to `@sblondon`_.)
v10.0 v10.0
----- -----
@@ -1516,6 +1530,7 @@ Features
.. _@nuschk: https://github.com/nuschk .. _@nuschk: https://github.com/nuschk
.. _@puru02: https://github.com/puru02 .. _@puru02: https://github.com/puru02
.. _@RignonNoel: https://github.com/RignonNoel .. _@RignonNoel: https://github.com/RignonNoel
.. _@sblondon: https://github.com/sblondon
.. _@sebashwa: https://github.com/sebashwa .. _@sebashwa: https://github.com/sebashwa
.. _@sebbacon: https://github.com/sebbacon .. _@sebbacon: https://github.com/sebbacon
.. _@slinkymanbyday: https://github.com/slinkymanbyday .. _@slinkymanbyday: https://github.com/slinkymanbyday

View File

@@ -27,6 +27,7 @@ a consistent API that avoids locking your code to one specific ESP
Anymail currently supports these ESPs: Anymail currently supports these ESPs:
* **Amazon SES** * **Amazon SES**
* **Brevo** (formerly SendinBlue)
* **MailerSend** * **MailerSend**
* **Mailgun** * **Mailgun**
* **Mailjet** * **Mailjet**
@@ -34,7 +35,6 @@ Anymail currently supports these ESPs:
* **Postal** (self-hosted ESP) * **Postal** (self-hosted ESP)
* **Postmark** * **Postmark**
* **SendGrid** * **SendGrid**
* **SendinBlue**
* **SparkPost** * **SparkPost**
Anymail includes: Anymail includes:

View File

@@ -26,7 +26,7 @@ class EmailBackend(AnymailRequestsBackend):
"api_url", "api_url",
esp_name=esp_name, esp_name=esp_name,
kwargs=kwargs, kwargs=kwargs,
default="https://api.sendinblue.com/v3/", default="https://api.brevo.com/v3/",
) )
if not api_url.endswith("/"): if not api_url.endswith("/"):
api_url += "/" api_url += "/"

View File

@@ -1,24 +1,30 @@
.. _brevo-backend:
.. _sendinblue-backend: .. _sendinblue-backend:
Sendinblue Brevo
========== =====
Anymail integrates with the `Sendinblue`_ email service, using their `API v3`_. Anymail integrates with the `Brevo`_ email service (formerly Sendinblue), using their `API v3`_.
Sendinblue's transactional API does not support some basic email features, such as Brevo's transactional API does not support some basic email features, such as
inline images. Be sure to review the :ref:`limitations <sendinblue-limitations>` below. inline images. Be sure to review the :ref:`limitations <sendinblue-limitations>` below.
.. versionchanged:: 10.1
Brevo was called "Sendinblue" until May, 2023. To avoid unnecessary code changes,
Anymail still uses the old name in code (settings, backend, webhook urls, etc.).
.. important:: .. important::
**Troubleshooting:** **Troubleshooting:**
If your Sendinblue messages aren't being delivered as expected, be sure to look for If your Brevo messages aren't being delivered as expected, be sure to look for
events in your Sendinblue `logs`_. events in your Brevo `logs`_.
Sendinblue detects certain types of errors only *after* the send API call reports Brevo detects certain types of errors only *after* the send API call reports
the message as "queued." These errors appear in the logging dashboard. the message as "queued." These errors appear in the logging dashboard.
.. _Sendinblue: https://www.sendinblue.com/ .. _Brevo: https://www.brevo.com/
.. _API v3: https://developers.sendinblue.com/docs .. _API v3: https://developers.brevo.com/docs
.. _logs: https://app-smtp.sendinblue.com/log .. _logs: https://app-smtp.brevo.com/log
Settings Settings
@@ -26,7 +32,7 @@ Settings
.. rubric:: EMAIL_BACKEND .. rubric:: EMAIL_BACKEND
To use Anymail's Sendinblue backend, set: To use Anymail's Brevo backend, set:
.. code-block:: python .. code-block:: python
@@ -39,10 +45,11 @@ in your settings.py.
.. rubric:: SENDINBLUE_API_KEY .. rubric:: SENDINBLUE_API_KEY
The API key can be retrieved from your Sendinblue `SMTP & API settings`_. The API key can be retrieved from your Brevo `SMTP & API settings`_ on the
"API Keys" tab (don't try to use an SMTP key). Required.
Make sure the version column indicates "v3." (v2 keys don't work with Make sure the version column indicates "v3." (v2 keys don't work with
Anymail. If you don't see a v3 key listed, use "Create a New API Key".) Anymail. If you don't see a v3 key listed, use "Create a New API Key".)
Required.
.. code-block:: python .. code-block:: python
@@ -55,30 +62,34 @@ Anymail will also look for ``SENDINBLUE_API_KEY`` at the
root of the settings file if neither ``ANYMAIL["SENDINBLUE_API_KEY"]`` root of the settings file if neither ``ANYMAIL["SENDINBLUE_API_KEY"]``
nor ``ANYMAIL_SENDINBLUE_API_KEY`` is set. nor ``ANYMAIL_SENDINBLUE_API_KEY`` is set.
.. _SMTP & API settings: https://account.sendinblue.com/advanced/api .. _SMTP & API settings: https://app.brevo.com/settings/keys/api
.. setting:: ANYMAIL_SENDINBLUE_API_URL .. setting:: ANYMAIL_SENDINBLUE_API_URL
.. rubric:: SENDINBLUE_API_URL .. rubric:: SENDINBLUE_API_URL
The base url for calling the Sendinblue API. The base url for calling the Brevo API.
The default is ``SENDINBLUE_API_URL = "https://api.sendinblue.com/v3/"`` The default is ``SENDINBLUE_API_URL = "https://api.brevo.com/v3/"``
(It's unlikely you would need to change this.) (It's unlikely you would need to change this.)
.. versionchanged:: 10.1
Earlier Anymail releases used ``https://api.sendinblue.com/v3/``.
.. _sendinblue-esp-extra: .. _sendinblue-esp-extra:
esp_extra support esp_extra support
----------------- -----------------
To use Sendinblue features not directly supported by Anymail, you can To use Brevo features not directly supported by Anymail, you can
set a message's :attr:`~anymail.message.AnymailMessage.esp_extra` to set a message's :attr:`~anymail.message.AnymailMessage.esp_extra` to
a `dict` that will be merged into the json sent to Sendinblue's a `dict` that will be merged into the json sent to Brevo's
`smtp/email API`_. `smtp/email API`_.
For example, you could set Sendinblue's *batchId* for use with For example, you could set Brevo's *batchId* for use with
their `batched scheduled sending`_: their `batched scheduled sending`_:
.. code-block:: python .. code-block:: python
@@ -91,8 +102,8 @@ their `batched scheduled sending`_:
(You can also set `"esp_extra"` in Anymail's :ref:`global send defaults <send-defaults>` (You can also set `"esp_extra"` in Anymail's :ref:`global send defaults <send-defaults>`
to apply it to all messages.) to apply it to all messages.)
.. _batched scheduled sending: https://developers.sendinblue.com/docs/schedule-batch-sendings .. _batched scheduled sending: https://developers.brevo.com/docs/schedule-batch-sendings
.. _smtp/email API: https://developers.sendinblue.com/v3.0/reference#sendtransacemail .. _smtp/email API: https://developers.brevo.com/reference/sendtransacemail
.. _sendinblue-limitations: .. _sendinblue-limitations:
@@ -100,61 +111,61 @@ to apply it to all messages.)
Limitations and quirks Limitations and quirks
---------------------- ----------------------
Sendinblue's v3 API has several limitations. In most cases below, Brevo's v3 API has several limitations. In most cases below,
Anymail will raise an :exc:`~anymail.exceptions.AnymailUnsupportedFeature` Anymail will raise an :exc:`~anymail.exceptions.AnymailUnsupportedFeature`
error if you try to send a message using missing features. You can error if you try to send a message using missing features. You can
override this by enabling the :setting:`ANYMAIL_IGNORE_UNSUPPORTED_FEATURES` override this by enabling the :setting:`ANYMAIL_IGNORE_UNSUPPORTED_FEATURES`
setting, and Anymail will try to limit the API request to features setting, and Anymail will try to limit the API request to features
Sendinblue can handle. Brevo can handle.
**HTML body required** **HTML body required**
Sendinblue's API returns an error if you attempt to send a message with Brevo's API returns an error if you attempt to send a message with
only a plain-text body. Be sure to :ref:`include HTML <sending-html>` only a plain-text body. Be sure to :ref:`include HTML <sending-html>`
content for your messages if you are not using a template. content for your messages if you are not using a template.
(Sendinblue *does* allow HTML without a plain-text body. This is generally (Brevo *does* allow HTML without a plain-text body. This is generally
not recommended, though, as some email systems treat HTML-only content as a not recommended, though, as some email systems treat HTML-only content as a
spam signal.) spam signal.)
**Inline images** **Inline images**
Sendinblue's v3 API doesn't support inline images, at all. Brevo's v3 API doesn't support inline images, at all.
(Confirmed with Sendinblue support Feb 2018.) (Confirmed with Brevo support Feb 2018.)
If you are ignoring unsupported features, Anymail will try to send If you are ignoring unsupported features, Anymail will try to send
inline images as ordinary image attachments. inline images as ordinary image attachments.
**Attachment names must be filenames with recognized extensions** **Attachment names must be filenames with recognized extensions**
Sendinblue determines attachment content type by assuming the attachment's Brevo determines attachment content type by assuming the attachment's
name is a filename, and examining that filename's extension (e.g., ".jpg"). name is a filename, and examining that filename's extension (e.g., ".jpg").
Trying to send an attachment without a name, or where the name does not end Trying to send an attachment without a name, or where the name does not end
in a supported filename extension, will result in a Sendinblue API error. in a supported filename extension, will result in a Brevo API error.
Anymail has no way to communicate an attachment's desired content-type Anymail has no way to communicate an attachment's desired content-type
to the Sendinblue API if the name is not set correctly. to the Brevo API if the name is not set correctly.
**Single Reply-To** **Single Reply-To**
Sendinblue's v3 API only supports a single Reply-To address. Brevo's v3 API only supports a single Reply-To address.
If you are ignoring unsupported features and have multiple reply addresses, If you are ignoring unsupported features and have multiple reply addresses,
Anymail will use only the first one. Anymail will use only the first one.
**Metadata** **Metadata**
Anymail passes :attr:`~anymail.message.AnymailMessage.metadata` to Sendinblue Anymail passes :attr:`~anymail.message.AnymailMessage.metadata` to Brevo
as a JSON-encoded string using their :mailheader:`X-Mailin-custom` email header. as a JSON-encoded string using their :mailheader:`X-Mailin-custom` email header.
The metadata is available in tracking webhooks. The metadata is available in tracking webhooks.
**Delayed sending** **Delayed sending**
.. versionadded:: 9.0 .. versionadded:: 9.0
Earlier versions of Anymail did not support :attr:`~anymail.message.AnymailMessage.send_at` Earlier versions of Anymail did not support :attr:`~anymail.message.AnymailMessage.send_at`
with Sendinblue. with Brevo.
**No click-tracking or open-tracking options** **No click-tracking or open-tracking options**
Sendinblue does not provide a way to control open or click tracking for individual Brevo does not provide a way to control open or click tracking for individual
messages. Anymail's :attr:`~anymail.message.AnymailMessage.track_clicks` and messages. Anymail's :attr:`~anymail.message.AnymailMessage.track_clicks` and
:attr:`~anymail.message.AnymailMessage.track_opens` settings are unsupported. :attr:`~anymail.message.AnymailMessage.track_opens` settings are unsupported.
**No envelope sender overrides** **No envelope sender overrides**
Sendinblue does not support overriding :attr:`~anymail.message.AnymailMessage.envelope_sender` Brevo does not support overriding :attr:`~anymail.message.AnymailMessage.envelope_sender`
on individual messages. on individual messages.
@@ -163,37 +174,16 @@ Sendinblue can handle.
Batch sending/merge and ESP templates Batch sending/merge and ESP templates
------------------------------------- -------------------------------------
Sendinblue supports :ref:`ESP stored templates <esp-stored-templates>` populated with Brevo supports :ref:`ESP stored templates <esp-stored-templates>` populated with
global merge data for all recipients, but does not offer :ref:`batch sending <batch-send>` global merge data for all recipients, but does not offer :ref:`batch sending <batch-send>`
with per-recipient merge data. Anymail's :attr:`~anymail.message.AnymailMessage.merge_data` with per-recipient merge data. Anymail's :attr:`~anymail.message.AnymailMessage.merge_data`
and :attr:`~anymail.message.AnymailMessage.merge_metadata` message attributes are not and :attr:`~anymail.message.AnymailMessage.merge_metadata` message attributes are not
supported with the Sendinblue backend, but you can use Anymail's supported with the Brevo backend, but you can use Anymail's
:attr:`~anymail.message.AnymailMessage.merge_global_data` with Sendinblue templates. :attr:`~anymail.message.AnymailMessage.merge_global_data` with Brevo templates.
Sendinblue supports two different template styles: a `new template language`_ To use a Brevo template, set the message's
that uses Django template syntax (with ``{{ param.NAME }}`` style substitutions),
and an "old" template language that used percent-delimited ``%NAME%`` style
substitutions. Anymail v7.0 and later require new style templates.
.. versionchanged:: 7.0
Anymail switched to a Sendinblue API that supports the new template language
and removes several limitations from the earlier template send API. But the new API
does not support attachments, and can behave oddly if used with old style templates.
.. caution::
Anymail v7.0 and later work *only* with Sendinblue's *new* template language. You should
follow Sendinblue's instructions to `convert each old template`_ to the new language.
Although unconverted old templates may appear to work with Anymail v7.0, some
features may not work properly. In particular, ``reply_to`` overrides and recipient
display names are silently ignored when *old* style templates are sent with the
*new* API used in Anymail v7.0.
To use a Sendinblue template, set the message's
:attr:`~anymail.message.AnymailMessage.template_id` to the numeric :attr:`~anymail.message.AnymailMessage.template_id` to the numeric
Sendinblue template ID, and supply substitution attributes using Brevo template ID, and supply substitution attributes using
the message's :attr:`~anymail.message.AnymailMessage.merge_global_data`: the message's :attr:`~anymail.message.AnymailMessage.merge_global_data`:
.. code-block:: python .. code-block:: python
@@ -203,7 +193,7 @@ the message's :attr:`~anymail.message.AnymailMessage.merge_global_data`:
# ...multiple to emails would all get the same message # ...multiple to emails would all get the same message
# (and would all see each other's emails in the "to" header) # (and would all see each other's emails in the "to" header)
) )
message.template_id = 3 # use this Sendinblue template message.template_id = 3 # use this Brevo template
message.from_email = None # to use the template's default sender message.from_email = None # to use the template's default sender
message.merge_global_data = { message.merge_global_data = {
'name': "Alice", 'name': "Alice",
@@ -211,9 +201,10 @@ the message's :attr:`~anymail.message.AnymailMessage.merge_global_data`:
'ship_date': "May 15", 'ship_date': "May 15",
} }
Within your Sendinblue template body and subject, you can refer to merge Within your Brevo template body and subject, you can refer to merge
variables using Django template syntax, like ``{{ params.order_no }}`` or variables using Django-like template syntax, like ``{{ params.order_no }}`` or
``{{ params.ship_date }}`` for the example above. ``{{ params.ship_date }}`` for the example above. See Brevo's guide to the
`Brevo Template Language`_.
The message's :class:`from_email <django.core.mail.EmailMessage>` (which defaults to The message's :class:`from_email <django.core.mail.EmailMessage>` (which defaults to
your :setting:`DEFAULT_FROM_EMAIL` setting) will override the template's default sender. your :setting:`DEFAULT_FROM_EMAIL` setting) will override the template's default sender.
@@ -223,12 +214,35 @@ If you want to use the template's sender, be sure to set ``from_email`` to ``Non
You can also override the template's subject and reply-to address (but not body) You can also override the template's subject and reply-to address (but not body)
using standard :class:`~django.core.mail.EmailMessage` attributes. using standard :class:`~django.core.mail.EmailMessage` attributes.
.. caution::
.. _new template language: **Sendinblue "old template language" not supported**
https://help.sendinblue.com/hc/en-us/articles/360000268730
Sendinblue once supported two different template styles: a "new" template
language that uses Django-like template syntax (with ``{{ param.NAME }}``
substitutions), and an "old" template language that used percent-delimited
``%NAME%`` substitutions.
Anymail 7.0 and later work *only* with new style templates, now known as the
"Brevo Template Language."
Although unconverted old templates may appear to work with Anymail, there can be
subtle bugs. In particular, ``reply_to`` overrides and recipient display names
are silently ignored when *old* style templates are sent with Anymail 7.0 or later.
If you still have old style templates, follow Brevo's instructions to
`convert each old template`_ to the new language.
.. versionchanged:: 7.0
Dropped support for Sendinblue old template language
.. _Brevo Template Language:
https://help.brevo.com/hc/en-us/articles/360000946299
.. _convert each old template: .. _convert each old template:
https://help.sendinblue.com/hc/en-us/articles/360000991960 https://help.brevo.com/hc/en-us/articles/360000991960
.. _sendinblue-webhooks: .. _sendinblue-webhooks:
@@ -237,7 +251,7 @@ Status tracking webhooks
------------------------ ------------------------
If you are using Anymail's normalized :ref:`status tracking <event-tracking>`, add If you are using Anymail's normalized :ref:`status tracking <event-tracking>`, add
the url at Sendinblue's site under `Transactional > Settings > Webhook`_. the url at Brevo's site under `Transactional > Email > Settings > Webhook`_.
The "URL to call" is: The "URL to call" is:
@@ -247,26 +261,26 @@ The "URL to call" is:
* *yoursite.example.com* is your Django site * *yoursite.example.com* is your Django site
Be sure to select the checkboxes for all the event types you want to receive. (Also make Be sure to select the checkboxes for all the event types you want to receive. (Also make
sure you are in the "Transactional" section of their site; Sendinblue has a separate set sure you are in the "Transactional" section of their site; Brevo has a separate set
of "Campaign" webhooks, which don't apply to messages sent through Anymail.) of "Campaign" webhooks, which don't apply to messages sent through Anymail.)
If you are interested in tracking opens, note that Sendinblue has both a "First opening" If you are interested in tracking opens, note that Brevo has both a "First opening"
and an "Opened" event type, and will generate both the first time a message is opened. and an "Opened" event type, and will generate both the first time a message is opened.
Anymail normalizes both of these events to "opened." To avoid double counting, you should Anymail normalizes both of these events to "opened." To avoid double counting, you should
only enable one of the two. only enable one of the two.
Sendinblue will report these Anymail :attr:`~anymail.signals.AnymailTrackingEvent.event_type`\s: Brevo will report these Anymail :attr:`~anymail.signals.AnymailTrackingEvent.event_type`\s:
queued, rejected, bounced, deferred, delivered, opened (see note above), clicked, complained, queued, rejected, bounced, deferred, delivered, opened (see note above), clicked, complained,
unsubscribed, subscribed (though this should never occur for transactional email). unsubscribed, subscribed (though this should never occur for transactional email).
For events that occur in rapid succession, Sendinblue frequently delivers them out of order. For events that occur in rapid succession, Brevo frequently delivers them out of order.
For example, it's not uncommon to receive a "delivered" event before the corresponding "queued." For example, it's not uncommon to receive a "delivered" event before the corresponding "queued."
The event's :attr:`~anymail.signals.AnymailTrackingEvent.esp_event` field will be The event's :attr:`~anymail.signals.AnymailTrackingEvent.esp_event` field will be
a `dict` of raw webhook data received from Sendinblue. a `dict` of raw webhook data received from Brevo.
.. _Transactional > Settings > Webhook: https://app-smtp.sendinblue.com/webhook .. _Transactional > Email > Settings > Webhook: https://app-smtp.brevo.com/webhook
.. _sendinblue-inbound: .. _sendinblue-inbound:
@@ -274,4 +288,7 @@ a `dict` of raw webhook data received from Sendinblue.
Inbound webhook Inbound webhook
--------------- ---------------
Sendinblue does not support inbound email handling. Anymail does not currently support `Brevo's inbound parsing`_.
.. _Brevo's inbound parsing:
https://developers.brevo.com/docs/inbound-parse-webhooks

View File

@@ -13,6 +13,7 @@ and notes about any quirks or limitations:
:maxdepth: 1 :maxdepth: 1
amazon_ses amazon_ses
brevo
mailersend mailersend
mailgun mailgun
mailjet mailjet
@@ -20,7 +21,6 @@ and notes about any quirks or limitations:
postal postal
postmark postmark
sendgrid sendgrid
sendinblue
sparkpost sparkpost
@@ -33,35 +33,33 @@ The table below summarizes the Anymail features supported for each ESP.
.. rst-class:: sticky-left .. rst-class:: sticky-left
============================================ ============ ============ =========== ========== =========== ========== ========== ========== ============ =========== ============================================ ============ ======= ============ =========== ========== =========== ========== ========== ========== ===========
Email Service Provider |Amazon SES| |MailerSend| |Mailgun| |Mailjet| |Mandrill| |Postal| |Postmark| |SendGrid| |Sendinblue| |SparkPost| Email Service Provider |Amazon SES| |Brevo| |MailerSend| |Mailgun| |Mailjet| |Mandrill| |Postal| |Postmark| |SendGrid| |SparkPost|
============================================ ============ ============ =========== ========== =========== ========== ========== ========== ============ =========== ============================================ ============ ======= ============ =========== ========== =========== ========== ========== ========== ===========
.. rubric:: :ref:`Anymail send options <anymail-send-options>` .. rubric:: :ref:`Anymail send options <anymail-send-options>`
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.envelope_sender` Yes No Domain only Yes Domain only Yes No No No Yes :attr:`~AnymailMessage.envelope_sender` Yes No No Domain only Yes Domain only Yes No No Yes
:attr:`~AnymailMessage.metadata` Yes No Yes Yes Yes No Yes Yes Yes Yes :attr:`~AnymailMessage.metadata` Yes Yes No Yes Yes Yes No Yes Yes Yes
:attr:`~AnymailMessage.merge_metadata` No No Yes Yes Yes No Yes Yes No Yes :attr:`~AnymailMessage.merge_metadata` No No No Yes Yes Yes No Yes Yes Yes
:attr:`~AnymailMessage.send_at` No Yes Yes No Yes No No Yes Yes Yes :attr:`~AnymailMessage.send_at` No Yes Yes Yes No Yes No No Yes Yes
:attr:`~AnymailMessage.tags` Yes Yes Yes Max 1 tag Yes Max 1 tag Max 1 tag Yes Yes Max 1 tag :attr:`~AnymailMessage.tags` Yes Yes Yes Yes Max 1 tag Yes Max 1 tag Max 1 tag Yes Max 1 tag
:attr:`~AnymailMessage.track_clicks` No Yes Yes Yes Yes No Yes Yes No Yes :attr:`~AnymailMessage.track_clicks` No No Yes Yes Yes Yes No Yes Yes Yes
:attr:`~AnymailMessage.track_opens` No Yes Yes Yes Yes No Yes Yes No Yes :attr:`~AnymailMessage.track_opens` No No Yes Yes Yes Yes No Yes Yes Yes
:ref:`amp-email` Yes No Yes No No No No Yes No Yes :ref:`amp-email` Yes No No Yes No No No No Yes Yes
.. rubric:: :ref:`templates-and-merge` .. rubric:: :ref:`templates-and-merge`
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.template_id` Yes Yes Yes Yes Yes No Yes Yes Yes Yes :attr:`~AnymailMessage.template_id` Yes Yes Yes Yes Yes Yes No Yes Yes Yes
:attr:`~AnymailMessage.merge_data` Yes Yes Yes Yes Yes No Yes Yes No Yes :attr:`~AnymailMessage.merge_data` Yes No Yes Yes Yes Yes No Yes Yes Yes
:attr:`~AnymailMessage.merge_global_data` Yes (emulated) (emulated) Yes Yes No Yes Yes Yes Yes :attr:`~AnymailMessage.merge_global_data` Yes Yes (emulated) (emulated) Yes Yes No Yes Yes Yes
.. rubric:: :ref:`Status <esp-send-status>` and :ref:`event tracking <event-tracking>` .. 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 :attr:`~AnymailMessage.anymail_status` Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
|AnymailTrackingEvent| from webhooks Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes |AnymailTrackingEvent| from webhooks Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
.. rubric:: :ref:`Inbound handling <inbound>` .. rubric:: :ref:`Inbound handling <inbound>`
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|AnymailInboundEvent| from webhooks Yes Yes Yes Yes Yes Yes Yes Yes No Yes |AnymailInboundEvent| from webhooks Yes No Yes Yes Yes Yes Yes Yes Yes Yes
============================================ ============ ============ =========== ========== =========== ========== ========== ========== ============ =========== ============================================ ============ ======= ============ =========== ========== =========== ========== ========== ========== ===========
Trying to choose an ESP? Please **don't** start with this table. It's far more Trying to choose an ESP? Please **don't** start with this table. It's far more
@@ -70,6 +68,7 @@ and support for developers. The *number* of extra features an ESP offers is almo
meaningless. (And even specific features don't matter if you don't plan to use them.) meaningless. (And even specific features don't matter if you don't plan to use them.)
.. |Amazon SES| replace:: :ref:`amazon-ses-backend` .. |Amazon SES| replace:: :ref:`amazon-ses-backend`
.. |Brevo| replace:: :ref:`brevo-backend`
.. |MailerSend| replace:: :ref:`mailersend-backend` .. |MailerSend| replace:: :ref:`mailersend-backend`
.. |Mailgun| replace:: :ref:`mailgun-backend` .. |Mailgun| replace:: :ref:`mailgun-backend`
.. |Mailjet| replace:: :ref:`mailjet-backend` .. |Mailjet| replace:: :ref:`mailjet-backend`
@@ -77,7 +76,6 @@ meaningless. (And even specific features don't matter if you don't plan to use t
.. |Postal| replace:: :ref:`postal-backend` .. |Postal| replace:: :ref:`postal-backend`
.. |Postmark| replace:: :ref:`postmark-backend` .. |Postmark| replace:: :ref:`postmark-backend`
.. |SendGrid| replace:: :ref:`sendgrid-backend` .. |SendGrid| replace:: :ref:`sendgrid-backend`
.. |Sendinblue| replace:: :ref:`sendinblue-backend`
.. |SparkPost| replace:: :ref:`sparkpost-backend` .. |SparkPost| replace:: :ref:`sparkpost-backend`
.. |AnymailTrackingEvent| replace:: :class:`~anymail.signals.AnymailTrackingEvent` .. |AnymailTrackingEvent| replace:: :class:`~anymail.signals.AnymailTrackingEvent`
.. |AnymailInboundEvent| replace:: :class:`~anymail.signals.AnymailInboundEvent` .. |AnymailInboundEvent| replace:: :class:`~anymail.signals.AnymailInboundEvent`

View File

@@ -12,14 +12,14 @@ authors = [
{name = "Anymail Contributors"}, {name = "Anymail Contributors"},
] ]
description = """\ description = """\
Django email backends and webhooks for Amazon SES, MailerSend, Mailgun, \ Django email backends and webhooks for Amazon SES, Brevo (Sendinblue),
Mailjet, Mandrill, Postal, Postmark, SendGrid, SendinBlue, and SparkPost\ MailerSend, Mailgun, Mailjet, Mandrill, Postal, Postmark, SendGrid, and SparkPost\
""" """
# readme: see tool.hatch.metadata.hooks.custom below # readme: see tool.hatch.metadata.hooks.custom below
keywords = [ keywords = [
"Django", "email", "email backend", "Django", "email", "email backend",
"ESP", "transactional mail", "ESP", "transactional mail",
"Amazon SES", "Amazon SES", "Brevo",
"MailerSend", "Mailgun", "Mailjet", "Mandrill", "MailerSend", "Mailgun", "Mailjet", "Mandrill",
"Postal", "Postmark", "Postal", "Postmark",
"SendGrid", "SendinBlue", "SparkPost", "SendGrid", "SendinBlue", "SparkPost",

View File

@@ -67,7 +67,7 @@ class SendinBlueBackendStandardEmailTests(SendinBlueBackendMockAPITestCase):
["to@example.com"], ["to@example.com"],
fail_silently=False, fail_silently=False,
) )
self.assert_esp_called("https://api.sendinblue.com/v3/smtp/email") self.assert_esp_called("https://api.brevo.com/v3/smtp/email")
http_headers = self.get_api_call_headers() http_headers = self.get_api_call_headers()
self.assertEqual(http_headers["api-key"], "test_api_key") self.assertEqual(http_headers["api-key"], "test_api_key")
self.assertEqual(http_headers["Content-Type"], "application/json") self.assertEqual(http_headers["Content-Type"], "application/json")

View File

@@ -112,7 +112,7 @@ class SendinBlueBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
metadata={"customer-id": "ZXK9123", "meta2": 2}, metadata={"customer-id": "ZXK9123", "meta2": 2},
) )
# Normal attachments don't work with Sendinblue templates: # Normal attachments don't work with Brevo templates:
# message.attach("attachment1.txt", "Here is some\ntext", "text/plain") # message.attach("attachment1.txt", "Here is some\ntext", "text/plain")
# If you can host the attachment content on some publicly-accessible URL, # If you can host the attachment content on some publicly-accessible URL,
# this *non-portable* alternative allows sending attachments with templates: # this *non-portable* alternative allows sending attachments with templates:
@@ -120,7 +120,7 @@ class SendinBlueBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
"attachment": [ "attachment": [
{ {
"name": "attachment1.txt", "name": "attachment1.txt",
# URL where Sendinblue can download the attachment content while # URL where Brevo can download the attachment content while
# sending (must be content-type: text/plain): # sending (must be content-type: text/plain):
"url": "https://raw.githubusercontent.com/anymail/django-anymail/" "url": "https://raw.githubusercontent.com/anymail/django-anymail/"
"main/docs/_readme/template.txt", "main/docs/_readme/template.txt",