Mailtrap

Added in version 14.0.

Anymail integrates with Mailtrap’s Email API/SMTP (transactional) and Email Sandbox (test) email services, using the Mailtrap API v2. (Anymail uses Mailtrap’s REST-oriented HTTP API, not the SMTP protocol.)

Anymail should also work correctly with Mailtrap’s Bulk Sending service (which uses an identical API), but this scenario is not tested separately.

Note

Troubleshooting: If your Mailtrap transactional or bulk messages aren’t being delivered as expected, check the Email Logs in Mailtrap’s dashboard. The “Event History” tab for an individual message is often helpful.

Settings

To use Anymail’s Mailtrap backend, set:

EMAIL_BACKEND = "anymail.backends.mailtrap.EmailBackend"
ANYMAIL = {
    "MAILTRAP_API_TOKEN": "<your API token>",
    # Only to use the Email Sandbox service:
    "MAILTRAP_SANDBOX_ID": <your test inbox id>,
}

in your settings.py.

When MAILTRAP_SANDBOX_ID is set, Anymail uses Mailtrap’s Email Sandbox service. If it is not set, Anymail uses Mailtrap’s transactional Email API/SMTP service.

MAILTRAP_API_TOKEN

Required for sending:

ANYMAIL = {
    ...
    "MAILTRAP_API_TOKEN": "<your API token>",
}

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

MAILTRAP_SANDBOX_ID

Required to use Mailtrap’s Email Sandbox test inbox. (And must not be set to use Mailtrap’s Email API/SMTP transactional service.)

ANYMAIL = {
    ...
    "MAILTRAP_SANDBOX_ID": 12345,
}

The sandbox id can be found in Mailtrap’s dashboard: click into the desired sandbox and look for the number in the dashboard url. For example, https://mailtrap.io/inboxes/12345/messages would be sandbox id 12345.

The value can be a string or number. For convenience when using env files, Anymail treats an empty string or None (or any falsy value) as “not set.”

MAILTRAP_API_URL

The base url for calling the Mailtrap API.

The default is MAILTRAP_API_URL = "https://send.api.mailtrap.io/api/" (Mailtrap’s Email API/SMTP transactional service) if MAILTRAP_SANDBOX_ID is not set, or "https://sandbox.api.mailtrap.io/api/" (Mailbox’s Email Sandbox testing service) when a sandbox id is provided.

Most users should not need to change this setting. However, you could set it to use Mailtrap’s bulk send service:

ANYMAIL = {
  ...
  "MAILTRAP_API_URL": "https://bulk.api.mailtrap.io/api/",
}

(Note that Anymail is not specifically tested with Mailtrap’s bulk API.)

The value must be only the API base URL: do not include the "/send" endpoint. (When provided, this is used as the base URL always. If you are also setting a sandbox id, the base URL must be compatible with Mailtrap’s sandbox API.)

esp_extra support

To use Mailtrap features not directly supported by Anymail, you can set a message’s esp_extra to a dict of Mailtraps’s Send email API body parameters. Your esp_extra dict will be deeply merged into the Mailtrap API payload, with esp_extra having precedence in conflicts. (For batch sends, the esp_extra values are merged into the "base" payload shared by all recipients.)

Example:

message.esp_extra = {
    "future_mailtrap_feature": "value"
}

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

Limitations and quirks

Single tag

Anymail uses Mailtrap’s "category" option for tags, and Mailtrap allows only a single category per message. If your message has two or more tags, you’ll get an AnymailUnsupportedFeature error—or if you’ve enabled ANYMAIL_IGNORE_UNSUPPORTED_FEATURES, Anymail will use only the first tag.

Tag not compatible with template

Trying to send with both tags and a template_id will result in a Mailtrap API error that “‘category’ is not allowed with ‘template_uuid’.”

No delayed sending

Mailtrap does not support send_at.

Attachments require filenames

Mailtrap requires that all attachments and inline images have filenames. If you don’t supply a filename, Anymail will use "attachment" as the filename.

Non-ASCII attachment filenames will be garbled

Mailtrap’s API does not properly encode Unicode characters in attachment filenames. Some email clients will display those characters incorrectly.

No click-tracking or open-tracking options

Mailtrap does not provide a way to control open or click tracking for individual messages. Anymail’s track_clicks and track_opens settings are unsupported. (You can exclude specific links from tracking using Mailtrap-proprietary attributes in your HTML.)

No envelope sender overrides

Mailtrap does not support overriding envelope_sender.

Non-ASCII mailboxes (EAI)

Mailtrap partially supports Unicode mailboxes (the user part of user@domain—see EAI). EAI recipient addresses (to, cc, bcc) are delivered correctly, but Mailtrap generates invalid header fields that may display as empty or garbled, depending on the email app.

Trying to use an EAI from_email results in a Mailtrap API error that the “‘From’ header does not match the sender’s domain.”

EAI in reply_to is supported (though may generate an invalid header field) for a single address. Using EAI with multiple reply addresses will cause an AnymailUnsupportedFeature error because Anymail cannot accurately communicate that to Mailtrap’s API.

Batch sending/merge and ESP templates

Mailtrap offers both ESP stored templates and batch sending with per-recipient merge data.

When you send a message with multiple to addresses, the merge_data, merge_metadata and merge_headers properties determine how many distinct messages are sent:

  • If the merge_... properties are not set (the default), Anymail will tell Mailtrap to send a single message, and all recipients will see the complete list of To addresses.

  • If any of the merge_... properties are set—even to an empty {} dict, Anymail will tell Mailtrap to send a separate message for each to address, and the recipients won’t see the other To addresses.

You can use a Mailtrap stored template by setting a message’s template_id to the template’s “Template UUID.” Find the template UUID in the Templates section of Mailtrap’s dashboard, under the template’s details. When a Mailtrap template is used, your Django code must not provide a message subject or text or html body.

Supply the template merge data values with Anymail’s normalized merge_data and merge_global_data message attributes.

message = EmailMessage(
    from_email="[email protected]",
    to=["[email protected]", "Bob <[email protected]>"],
    # omit subject and body (or set to None) to use template content
    ...
)
message.template_id = "11111111-abcd-1234-0000-0123456789ab"  # Template UUID
message.merge_data = {
    '[email protected]': {'name': "Alice", 'order_no': "12345"},
    '[email protected]': {'name': "Bob", 'order_no': "54321"},
}
message.merge_global_data = {
    'ship_date': "May 15",
}
message.send()

Status tracking webhooks

If you are using Anymail’s normalized status tracking, create a webhook in the Settings section of the Mailtrap dashboard under Webhooks. See their Webhooks help article for more information.

(Note that Mailtrap’s Email Sandbox service does not trigger webhook events.)

In Mailtrap’s “Add new webhook” screen, enter:

  • Webhook URL:

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

  • Payload format: JSON (not JSON Lines)

  • Select area: Email Sending

    • Select stream: Transactional (unless you have overridden Anymail’s MAILTRAP_API_URL to use Mailtrap’s bulk sending API).

    • Select domain: the desired sending domain(s)

    • Select events to listen to: check all you want to receive

Mailtrap will report these Anymail event_types: rejected, bounced, deferred, delivered, opened, clicked, complained, unsubscribed.

Inbound webhook

Mailtrap’s inbound service is currently under development, and APIs are not yet publicly available.