Mailjet: add docs

This commit is contained in:
medmunds
2017-07-13 15:43:11 -07:00
parent d6d8044066
commit 54d2fe2513
4 changed files with 277 additions and 23 deletions

View File

@@ -1,5 +1,5 @@
Anymail: Django email backends for Mailgun, Postmark, SendGrid, SparkPost and more
==================================================================================
Anymail: Django email backends for Mailgun, Mailjet, Postmark, SendGrid, SparkPost and more
===========================================================================================
**PRE-1.0**
@@ -32,7 +32,7 @@ Anymail integrates several transactional email service providers (ESPs) into Dja
with a consistent API that lets you use ESP-added features without locking your code
to a particular ESP.
It currently fully supports Mailgun, Postmark, SendGrid, and SparkPost,
It currently fully supports Mailgun, Mailjet, Postmark, SendGrid, and SparkPost,
and has limited support for Mandrill.
Anymail normalizes ESP functionality so it "just works" with Django's
@@ -75,7 +75,7 @@ Anymail 1-2-3
.. This quickstart section is also included in docs/quickstart.rst
This example uses Mailgun, but you can substitute Postmark or SendGrid
This example uses Mailgun, but you can substitute Mailjet or Postmark or SendGrid
or SparkPost or any other supported ESP where you see "mailgun":
1. Install Anymail from PyPI:

View File

@@ -13,6 +13,7 @@ and notes about any quirks or limitations:
:maxdepth: 1
mailgun
mailjet
mandrill
postmark
sendgrid
@@ -26,28 +27,28 @@ The table below summarizes the Anymail features supported for each ESP.
.. currentmodule:: anymail.message
============================================ ========== ========== ========== ========== ===========
Email Service Provider |Mailgun| |Mandrill| |Postmark| |SendGrid| |SparkPost|
============================================ ========== ========== ========== ========== ===========
============================================ ========== ========== ========== ========== ========== ===========
Email Service Provider |Mailgun| |Mailjet| |Mandrill| |Postmark| |SendGrid| |SparkPost|
============================================ ========== ========== ========== ========== ========== ===========
.. rubric:: :ref:`Anymail send options <anymail-send-options>`
---------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.metadata` Yes Yes No Yes Yes
:attr:`~AnymailMessage.send_at` Yes Yes No Yes Yes
:attr:`~AnymailMessage.tags` Yes Yes Max 1 tag Yes Max 1 tag
:attr:`~AnymailMessage.track_clicks` Yes Yes Yes Yes Yes
:attr:`~AnymailMessage.track_opens` Yes Yes Yes Yes Yes
---------------------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.metadata` Yes Yes Yes No Yes Yes
:attr:`~AnymailMessage.send_at` Yes No Yes No Yes Yes
:attr:`~AnymailMessage.tags` Yes Max 1 tag Yes Max 1 tag Yes Max 1 tag
:attr:`~AnymailMessage.track_clicks` Yes Yes Yes Yes Yes Yes
:attr:`~AnymailMessage.track_opens` Yes Yes Yes Yes Yes Yes
.. rubric:: :ref:`templates-and-merge`
---------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.template_id` No Yes Yes Yes Yes
:attr:`~AnymailMessage.merge_data` Yes Yes No Yes Yes
:attr:`~AnymailMessage.merge_global_data` (emulated) Yes Yes Yes Yes
---------------------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.template_id` No Yes Yes Yes Yes Yes
:attr:`~AnymailMessage.merge_data` Yes Yes Yes No Yes Yes
:attr:`~AnymailMessage.merge_global_data` (emulated) 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
|AnymailTrackingEvent| from webhooks Yes Yes Yes Yes Yes
============================================ ========== ========== ========== ========== ===========
---------------------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.anymail_status` Yes Yes Yes Yes Yes Yes
|AnymailTrackingEvent| from webhooks Yes Yes Yes Yes Yes Yes
============================================ ========== ========== ========== ========== ========== ===========
Trying to choose an ESP? Please **don't** start with this table. It's far more
@@ -56,6 +57,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.)
.. |Mailgun| replace:: :ref:`mailgun-backend`
.. |Mailjet| replace:: :ref:`mailjet-backend`
.. |Mandrill| replace:: :ref:`mandrill-backend`
.. |Postmark| replace:: :ref:`postmark-backend`
.. |SendGrid| replace:: :ref:`sendgrid-backend`

252
docs/esps/mailjet.rst Normal file
View File

@@ -0,0 +1,252 @@
.. _mailjet-backend:
Mailjet
=======
Anymail integrates with the `Mailjet`_ email service, using their transactional `Send API`_ (v3).
.. versionadded:: 0.11
.. _mailjet-v31-api:
.. note::
Mailjet is developing an improved `v3.1 Send API`_ (in public beta as of mid-2017).
Once the v3.1 API is released, Anymail will switch to it. This change should be
largely transparent to your code, unless you are using Anymail's
:ref:`esp_extra <mailjet-esp-extra>` feature to set API-specific options.
.. _Mailjet: https://www.mailjet.com/
.. _Send API: https://dev.mailjet.com/guides/#choose-sending-method
.. _v3.1 Send API: https://dev.mailjet.com/guides/#send-api-v3-1-beta
Settings
--------
.. rubric:: EMAIL_BACKEND
To use Anymail's Mailjet backend, set:
.. code-block:: python
EMAIL_BACKEND = "anymail.backends.mailjet.EmailBackend"
in your settings.py.
.. setting:: ANYMAIL_MAILJET_API_KEY
.. rubric:: MAILJET_API_KEY and MAILJET_SECRET_KEY
Your Mailjet API key and secret, from your Mailjet account REST API settings
under `API Key Management`_. (Mailjet's documentation also sometimes uses
"API private key" to mean the same thing as "API secret.")
.. code-block:: python
ANYMAIL = {
...
"MAILJET_API_KEY": "<your API key>",
"MAILJET_API_SECRET": "<your API secret>",
}
You can use either a master or sub-account API key.
Anymail will also look for ``MAILJET_API_KEY`` and ``MAILJET_API_SECRET`` at the
root of the settings file if neither ``ANYMAIL["MAILJET_API_KEY"]``
nor ``ANYMAIL_MAILJET_API_KEY`` is set.
.. _API Key Management: https://app.mailjet.com/account/api_keys
.. setting:: ANYMAIL_MAILJET_API_URL
.. rubric:: MAILJET_API_URL
The base url for calling the Mailjet API.
The default is ``MAILJET_API_URL = "https://api.mailjet.com/v3"``
(It's unlikely you would need to change this. This setting cannot be used
to opt into a newer API version; the parameters are not backwards compatible.)
.. _mailjet-esp-extra:
esp_extra support
-----------------
To use Mailjet features not directly supported by Anymail, you can
set a message's :attr:`~anymail.message.AnymailMessage.esp_extra` to
a `dict` of Mailjet's `Send API json properties`_.
Your :attr:`esp_extra` dict will be merged into the
parameters Anymail has constructed for the send, with `esp_extra`
having precedence in conflicts.
.. note::
Any ``esp_extra`` settings will need to be updated when Anymail changes
to use Mailjet's upcoming v3.1 API. (See :ref:`note above <mailjet-v31-api>`.)
Example:
.. code-block:: python
message.esp_extra = {
# Mailjet v3.0 Send API options:
"Mj-prio": 3, # Use Mailjet critically-high priority queue
"Mj-CustomID": my_event_tracking_id,
}
(You can also set `"esp_extra"` in Anymail's
:ref:`global send defaults <send-defaults>` to apply it to all
messages.)
.. _Send API json properties: https://dev.mailjet.com/guides/#send-api-json-properties
Limitations and quirks
----------------------
**Single tag**
Anymail uses Mailjet's `campaign`_ option for tags, and Mailjet allows
only a single campaign 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.
.. _campaign: https://dev.mailjet.com/guides/#grouping-into-a-campaign
**No delayed sending**
Mailjet does not support :attr:`~anymail.message.AnymailMessage.send_at`.
**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.
(Tested July, 2017, and confirmed with Mailjet API support.)
If your message would be affected, Anymail attempts to work around
the problem by switching to `MIME encoded-word`_ syntax where needed.
Most modern email clients should support this syntax, but if you run
into issues either avoid using ``cc`` and ``bcc``, or strip commas from all
recipient names (in ``to``, ``cc``, *and* ``bcc``) before sending.
.. _MIME encoded-word: https://en.wikipedia.org/wiki/MIME#Encoded-Word
**Merge data not compatible with cc/bcc**
Mailjet's v3 API is not capable of representing both ``cc`` or ``bcc`` fields
and :attr:`~anymail.message.AnymailMessage.merge_data` in the same message.
If you attempt to combine them, Anymail will raise an error at send time.
(The latter two limitations should be resolved in a future release when
Anymail :ref:`switches <mailjet-v31-api>` to Mailjet's upcoming v3.1 API.)
.. _mailjet-templates:
Batch sending/merge and ESP templates
-------------------------------------
Mailjet offers both :ref:`ESP stored templates <esp-stored-templates>`
and :ref:`batch sending <batch-send>` with per-recipient merge data.
You can use a Mailjet stored transactional template by setting a message's
:attr:`~anymail.message.AnymailMessage.template_id` to the
template's *numeric* template ID. (*Not* the template's name. To get the
numeric template id, click on the name in your Mailjet `transactional templates`_,
then look for "Template ID" above the preview that appears.)
Supply the template merge data values with Anymail's
normalized :attr:`~anymail.message.AnymailMessage.merge_data`
and :attr:`~anymail.message.AnymailMessage.merge_global_data`
message attributes.
.. code-block:: python
message = EmailMessage(
...
# omit subject and body (or set to None) to use template content
to=["alice@example.com", "Bob <bob@example.com>"]
)
message.template_id = "176375" # Mailjet numeric template id
message.from_email = None # Use the From address stored with the template
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",
}
Any ``from_email`` in your EmailMessage will override the template's default sender
address. To use the template's sender, you must explicitly set ``from_email = None``
after creating the EmailMessage, as shown above. (If you omit this, Django's default
:setting:`DEFAULT_FROM_EMAIL` will be used.)
Instead of creating a stored template at Mailjet, you can also refer to merge fields
directly in an EmailMessage's body---the message itself is used as an on-the-fly template:
.. code-block:: python
message = EmailMessage(
from_email="orders@example.com",
to=["alice@example.com", "Bob <bob@example.com>"],
subject="Your order has shipped", # subject doesn't support on-the-fly merge fields
# Use [[var:FIELD]] to for on-the-fly merge into plaintext or html body:
body="Dear [[var:name]]: Your order [[var:order_no]] shipped on [[var:ship_date]]."
)
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",
}
(Note that on-the-fly templates use square brackets to indicate `"personalization"`_ merge fields,
rather than the curly brackets used with stored templates in Mailjet's template language.)
See Mailjet's `template documentation`_ and `template language`_ docs
for more information.
.. _transactional templates: https://app.mailjet.com/templates/transactional
.. _"personalization": https://dev.mailjet.com/guides/#personalisation
.. _template documentation: https://www.mailjet.com/docs/template_builder_transactional
.. _template language: https://dev.mailjet.com/template-language/
.. _mailjet-webhooks:
Status tracking webhooks
------------------------
If you are using Anymail's normalized :ref:`status tracking <event-tracking>`, enter
the url in your Mailjet account REST API settings under `Event tracking (triggers)`_:
:samp:`https://{random}:{random}@{yoursite.example.com}/anymail/mailjet/tracking/`
* *random:random* is an :setting:`ANYMAIL_WEBHOOK_AUTHORIZATION` shared secret
* *yoursite.example.com* is your Django site
Be sure to enter the URL in the Mailjet settings for all the event types you want to receive.
It's also recommended to select the "group events" checkbox for each trigger, to minimize your
server load.
Mailjet will report these Anymail :attr:`~anymail.signals.AnymailTrackingEvent.event_type`\s:
rejected, bounced, deferred, delivered, opened, clicked, complained, unsubscribed.
The event's :attr:`~anymail.signals.AnymailTrackingEvent.esp_event` field will be
a `dict` of `Mailjet event`_ fields, for a single event. (Although Mailjet calls
webhooks with batches of events, Anymail will invoke your signal receiver separately
for each event in the batch.)
.. _Event tracking (triggers): https://app.mailjet.com/account/triggers
.. _Mailjet event: https://dev.mailjet.com/guides/#events

View File

@@ -1,5 +1,5 @@
Anymail: Django email backends for Mailgun, Postmark, SendGrid and more
=======================================================================
Anymail: Django email backends for Mailgun, Mailjet, Postmark, SendGrid and more
================================================================================
Version |release|