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.)
Note that this setting also affects inbound webhooks, which must call Mailtrap
APIs to retrieve inbound messages. The default for inbound webhooks is
"https://mailtrap.io/api/". If you are using both inbound email and
sending, it’s best to not set this setting and instead supply an api_url
option for sending in Django’s MAILERS configuration or a call to
django.core.mail.get_connection().
MAILTRAP_TRACKING_SECRET
The Mailtrap webhook signing secret for tracking (email sending) webhooks. This is generated by Mailtrap after you create a webhook.
MAILTRAP_INBOUND_SECRET
The Mailtrap webhook signing secret for inbound webhooks. This is generated by Mailtrap after you create a webhook.
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 moretags, you’ll get anAnymailUnsupportedFeatureerror—or if you’ve enabledANYMAIL_IGNORE_UNSUPPORTED_FEATURES, Anymail will use only the first tag.- Tag not compatible with template
Trying to send with both
tagsand atemplate_idwill 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_clicksandtrack_openssettings 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_emailresults in a Mailtrap API error that the “‘From’ header does not match the sender’s domain.”EAI in
reply_tois supported (though may generate an invalid header field) for a single address. Using EAI with multiple reply addresses will cause anAnymailUnsupportedFeatureerror 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 eachtoaddress, 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.)
Mailtrap supports signed webhook events. You can configure Anymail’s tracking
webhook to verify Mailtrap’s signature, require a WEBHOOK_SECRET shared secret, or both. Using at least signature
verification is recommended.
Added in version 15.2: Support for verifying Mailtrap webhook signatures.
To configure an event tracking webhook, in Mailtrap’s “Add new webhook” screen enter:
Webhook URL:
If are not using Anymail’s shared webhook secret:
https://yoursite.example.com/anymail/mailtrap/tracking/Or if you are using Anymail’s
WEBHOOK_SECRET, include the random:random shared secret in the URL:https://random:random@yoursite.example.com/anymail/mailtrap/tracking/where yoursite.example.com is your Django site.
Payload format: JSON (not JSON Lines)
Select area: Email Sending
Select stream: Transactional (unless you have overridden Anymail’s
MAILTRAP_API_URLto use Mailtrap’s bulk sending API).Select domain: the desired sending domain(s)
Select events to listen to: check all you want to receive
After you have created the webhook, the signing secret will become available in
Mailtrap’s webhooks list—see Getting your signing secret in Mailtrap’s
documentation. To enable signature verification, copy the secret and provide it
as Anymail’s MAILTRAP_TRACKING_SECRET in your Django settings:
ANYMAIL = {
# ...
"MAILTRAP_TRACKING_SECRET": "<signing secret from Mailtrap>",
}
Mailtrap will report these Anymail event_types:
rejected, bounced, deferred, delivered, opened, clicked, complained, unsubscribed.
Inbound webhook
Added in version 15.2.
To receive email from Mailtrap through Anymail’s normalized inbound handling, first follow Mailtrap’s guide to set up a Mailtrap inbound inbox. Then configure a Mailtrap webhook to notify Anymail of new inbound messages. In their “Add new webhook” screen enter:
Webhook URL:
Using Anymail’s shared webhook secret is optional if you enable Mailtrap webhook signature verification. If you are not using a shared secret, enter:
https://yoursite.example.com/anymail/mailtrap/inbound/Or if you are using Anymail’s
WEBHOOK_SECRET, include the random:random shared secret in the URL:https://random:random@yoursite.example.com/anymail/mailtrap/inbound/where yoursite.example.com is your Django site.
Payload format: JSON (not JSON Lines)
Select area: Inbound inboxes. You can choose “Account-wide (all inboxes)” or a specific inbox.
After you have created the webhook, the signing secret will become available in
Mailtrap’s webhooks list—see Getting your signing secret in Mailtrap’s
documentation. To enable signature verification, copy the secret and provide it
as Anymail’s MAILTRAP_INBOUND_SECRET in your Django settings. (Note that inbound
and tracking webhooks use different secrets, so have different setting names.)
The inbound webhook must retrieve inbound message data from Mailtrap’s API.
Ensure your Anymail settings include a MAILTRAP_API_TOKEN that has at least “viewer” permission for the
selected inbox(es) in the “Inbound” section (as well as “admin” permission
on any sending domains, if you are also sending through Mailtrap).
ANYMAIL = {
# ...
# Required for inbound:
"MAILTRAP_API_TOKEN": "<token with inbound viewer permission>",
# Include to enable Mailtrap webhook signature verification:
"MAILTRAP_INBOUND_SECRET": "<signing secret from Mailtrap>",
}
In your inbound signal receiver, the event.esp_event will be set to the result of Mailtrap’s get
an inbound message API. The "inbox_id" and "id" (inbound message id)
fields may be useful for (e.g.,) calling Mailtrap’s API to delete the inbound
message after you have processed it