When using a stored template, SparkPost disallows
subject, text, and html. Django's EmailMessage default
empty strings are enough to provoke "Both content
object and template_id are specified" from SparkPost,
so remove them (if empty) when using stored templates.
Update docs and tests; add integration test for template_id.
Fixes#24
Install default warnings filter in test runs, to avoid
python's default suppression of DeprecationWarning
and other "intended for developer" warnings.
(Avoids need to provide -Wd or -Wall arg to runtests.)
* Merge esp_extra with Mandrill send payload
* Handle pythonic forms of `recipient_metadata`
and `template_content` in esp_extra
* DeprecationWarning for Mandrill EmailMessage
attributes inherited from Djrill
* message.template_id to use ESP stored templates
* message.merge_data and merge_global_data
to supply per-recipient/global merge variables
(with or without an ESP stored template)
* When using per-recipient merge_data, tell ESP to use
batch send: individual message per "to" address.
(Mailgun does this automatically; SendGrid requires
using a different "to" field; Mandrill requires
`preserve_recipients=False`; Postmark doesn't
support *this type* of batch sending with merge data.)
* Allow message.from_email=None (must be set after
init) and message.subject=None to suppress those
fields in API calls (for ESPs that allow "From" and
"Subject" in their template definitions).
Mailgun:
* Emulate merge_global_data by copying to
recipient-variables for each recipient.
SendGrid:
* Add delimiters to merge field names via
esp_extra['merge_field_format'] or
ANYMAIL_SENDGRID_MERGE_FIELD_FORMAT setting.
Mandrill:
* Remove Djrill versions of these features;
update migration notes.
Closes#5.
Previously, setting esp_extra['x-smtpapi']['filters']
would override the entire filters setting, potentially
undoing other Anymail options that use SendGrid
filters (like track_opens).
Now, 'filters' is special-cased, and merged with
any other Anymail filter options.
(We don't do a fully deep merge, because otherwise
there would be no way to use esp_extra to *clear*
Anymail settings.)
* Update utils.get_anymail_setting to support
kwargs override of django.conf.settings values
* Use the updated version everywhere
* Switch from ImproperlyConfigured to
AnymailConfigurationError exception
(anticipates feature_wehooks change)
Closes#12
* Add smtp-id in unique_args (metadata), to ensure
it shows up in click and open events.
* Add SENDGRID_GENERATE_MESSAGE_ID setting,
default True, to control auto-Message-ID behavior.
* Document it.
Simplify install to just `pip install django-anymail`.
(Rather than `... django-anymail[mailgun]`
All of the ESPs so far require requests, so just move
that into the base requirements. (Chances are your
Django app already needs requests for some other
reason, anyway.)
Truly unique ESP dependencies (e.g., boto for
AWS-SES) could still use the setup extra features
mechanism.
* Add filename param to attach_inline_image
* Add attach_inline_image_file function
(parallels EmailMessage.attach and attach_file)
* Use `Content-Disposition: inline` to decide
whether an attachment should be handled inline
(whether or not it's an image, and whether or not
it has a Content-ID)
* Stop conflating filename and Content-ID, for
ESPs that allow both. (Solves problem where
Google Inbox was displaying inline images
as attachments when sent through SendGrid.)
Webhook tests define a local signal receiver function,
so connect it using the `weak=False` option to set
a good example.
(This isn't technically needed in the tests: the test receivers
are only connected while their definitions are still in scope,
so they couldn't possibly be garbage collected. But it doesn't
hurt, and it's good practice in case the test code gets copied.)
Also update the webhook docs to have a direct link to
Django's "listening to signals" info.
* Break apart massive _send call
* Try to facilitate subclassing
* Centralize fail_silently handling during _send
* Include original EmailMessage as exception attr
* Add common base DjrillException
* Simplify backend by moving logic
to describe errors into base DjrillException
* Add NotSerializableForMandrillError
for JSON serialization errors
Raise new MandrillRecipientsRefused exception
when Mandrill returns 'reject' or 'invalid' status
for *all* recipients of a message.
(Similar to Django's SMTP email backend raising
SMTPRecipientsRefused.)
Add setting MANDRILL_IGNORE_RECIPIENT_STATUS
to override the new exception.
Trap JSON parsing errors in Mandrill API response,
and raise MandrillAPIError for them. (Helps with #93.)
Closes#80.
Closes#81.