Sendinblue

Anymail integrates with the Sendinblue email service, using their API v3. Sendinblue’s transactional API does not support some basic email features, such as inline images. Be sure to review the limitations below.

Important

Troubleshooting: If your Sendinblue messages aren’t being delivered as expected, be sure to look for events in your Sendinblue logs.

Sendinblue detects certain types of errors only after the send API call reports the message as “queued.” These errors appear in the logging dashboard.

Settings

EMAIL_BACKEND

To use Anymail’s Sendinblue backend, set:

EMAIL_BACKEND = "anymail.backends.sendinblue.EmailBackend"

in your settings.py.

SENDINBLUE_API_KEY

The API key can be retrieved from your Sendinblue SMTP & API settings. 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”.) Required.

ANYMAIL = {
    ...
    "SENDINBLUE_API_KEY": "<your v3 API key>",
}

Anymail will also look for SENDINBLUE_API_KEY at the root of the settings file if neither ANYMAIL["SENDINBLUE_API_KEY"] nor ANYMAIL_SENDINBLUE_API_KEY is set.

SENDINBLUE_API_URL

The base url for calling the Sendinblue API.

The default is SENDINBLUE_API_URL = "https://api.sendinblue.com/v3/" (It’s unlikely you would need to change this.)

esp_extra support

To use Sendinblue features not directly supported by Anymail, you can set a message’s esp_extra to a dict that will be merged into the json sent to Sendinblue’s smtp/email API.

Example:

message.esp_extra = {
    'hypotheticalFutureSendinblueParam': '2022',  # merged into send params
}

(You can also set "esp_extra" in Anymail’s global send defaults to apply it to all messages.)

Limitations and quirks

Sendinblue’s v3 API has several limitations. In most cases below, Anymail will raise an AnymailUnsupportedFeature error if you try to send a message using missing features. You can override this by enabling the ANYMAIL_IGNORE_UNSUPPORTED_FEATURES setting, and Anymail will try to limit the API request to features Sendinblue can handle.

HTML body required

Sendinblue’s API returns an error if you attempt to send a message with only a plain-text body. Be sure to include HTML content for your messages if you are not using a template.

(Sendinblue does allow HTML without a plain-text body. This is generally not recommended, though, as some email systems treat HTML-only content as a spam signal.)

Inline images

Sendinblue’s v3 API doesn’t support inline images, at all. (Confirmed with Sendinblue support Feb 2018.)

If you are ignoring unsupported features, Anymail will try to send inline images as ordinary image attachments.

Attachment names must be filenames with recognized extensions

Sendinblue determines attachment content type by assuming the attachment’s 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 in a supported filename extension, will result in a Sendinblue API error. Anymail has no way to communicate an attachment’s desired content-type to the Sendinblue API if the name is not set correctly.

Single Reply-To

Sendinblue’s v3 API only supports a single Reply-To address.

If you are ignoring unsupported features and have multiple reply addresses, Anymail will use only the first one.

Metadata
Anymail passes metadata to Sendinblue as a JSON-encoded string using their X-Mailin-custom email header. The metadata is available in tracking webhooks.
No delayed sending
Sendinblue does not support send_at.
No click-tracking or open-tracking options
Sendinblue does not provide a way to control open or click tracking for individual messages. Anymail’s track_clicks and track_opens settings are unsupported.
No envelope sender overrides
Sendinblue does not support overriding envelope_sender on individual messages.

Batch sending/merge and ESP templates

Sendinblue supports ESP stored templates populated with global merge data for all recipients, but does not offer batch sending with per-recipient merge data. Anymail’s merge_data and merge_metadata message attributes are not supported with the Sendinblue backend, but you can use Anymail’s merge_global_data with Sendinblue templates.

Sendinblue supports two different template styles: a new template language 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.

Changed in version 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 template_id to the numeric Sendinblue template ID, and supply substitution attributes using the message’s merge_global_data:

message = EmailMessage(
    to=["alice@example.com"]  # single recipient...
    # ...multiple to emails would all get the same message
    # (and would all see each other's emails in the "to" header)
)
message.template_id = 3   # use this Sendinblue template
message.from_email = None  # to use the template's default sender
message.merge_global_data = {
    'name': "Alice",
    'order_no': "12345",
    'ship_date': "May 15",
}

Within your Sendinblue template body and subject, you can refer to merge variables using Django template syntax, like {{ params.order_no }} or {{ params.ship_date }} for the example above.

The message’s from_email (which defaults to your DEFAULT_FROM_EMAIL setting) will override the template’s default sender. If you want to use the template’s sender, be sure to set from_email to None after creating the message, as shown in the example above.

You can also override the template’s subject and reply-to address (but not body) using standard EmailMessage attributes.

Status tracking webhooks

If you are using Anymail’s normalized status tracking, add the url at Sendinblue’s site under Transactional > Settings > Webhook.

The “URL to call” is:

https://random:random@yoursite.example.com/anymail/sendinblue/tracking/

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 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” 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 only enable one of the two.

Sendinblue will report these Anymail event_types: queued, rejected, bounced, deferred, delivered, opened (see note above), clicked, complained, 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 example, it’s not uncommon to receive a “delivered” event before the corresponding “queued.”

The event’s esp_event field will be a dict of raw webhook data received from Sendinblue.

Inbound webhook

Sendinblue does not support inbound email handling.