Commit Graph

109 Commits

Author SHA1 Message Date
medmunds
dc0a46a815 Feature: add is_batch_send to anymail_test_params
Make it easier for tests to check whether messages
would fall under Anymail's batch-send logic.

See #249.
2022-01-11 19:54:39 -08:00
medmunds
60fbe1e896 Fix: treat first text/plain alternative as plaintext body
Improve handling of alternative parts and `content_subtype`
to match how Django's SMTP backend handles some unusual cases.

Change Test backend to support (and record) text/* alternative
parts. (But still reject other types of alternatives.)

Fixes #252
2022-01-10 15:35:00 -08:00
Tilmann Becker
e90c10b546 Add Postal support
Thanks to @tiltec for researching, implementing, testing and documenting it.
2021-06-07 17:11:35 -07:00
Mike Edmunds
44754c908e Postmark: fix silent failures for send-time validation errors
Postmark uses their ErrorCode 300 to report several different
send-time validation errors, some of which identify invalid
recipients that need to be handled specially, but many of which
are ordinary API errors.

Rework the logic for parsing ErrorCode 300 error messages:
Handle only "Invalid 'To'" or "Error parsing 'To'" (or 'Cc'
or 'Bcc') as recipient errors. Otherwise raise an API error.

Fixes #238 silent failure when sending with long metadata keys.
2021-05-19 13:15:34 -07:00
medmunds
f4c99abddf Postmark: Fix incorrect single 'to' handling with template but no merge data
Fixes #227
2021-02-24 12:30:05 -08:00
medmunds
9ed5ce0213 Postmark: Fix API error with template but no merge data
Fixes #223
2021-02-22 17:50:46 -08:00
medmunds
d1ef61d3ba Mailgun: add AMPHTML support 2021-01-27 14:37:16 -08:00
medmunds
d33c9ea4ed Mailgun: improve API error messages 2021-01-27 14:37:16 -08:00
Mike Edmunds
8c1749c6f3 SparkPost: drop support for multiple from_email (#213)
SparkPost's API no longer allows this, and now returns
a confusing error message about return_path.

(Not treating as a breaking change in Anymail, because
the breaking change was in the SparkPost API. This just
improves the error message in the unlikely event anyone
is trying to use this feature.)

Closes #212
2020-11-28 18:02:59 -08:00
medmunds
feee8b5c5a Cleanup: simplify requests backend raise_for_status
Treat all 2xx (not just 200) as success in base
AnymailRequestsBackend.raise_for_status, eliminating
some unnecessary subclass overrides.
2020-09-11 14:26:55 -07:00
medmunds
a14276e765 Cleanup: remove unused MailjetPayload property 2020-09-11 14:26:55 -07:00
medmunds
985143b234 SparkPost: add subaccount support 2020-09-11 11:10:24 -07:00
medmunds
61660cd5ff SparkPost: call HTTP API directly [breaking]
Switch from the (now unmaintained) python-sparkpost
client library to a requests-based backend that calls
SparkPost's Transmissions API directly.

Also adds support for text/x-amp-html alternative parts
(which are supported by the SparkPost API, but weren't
by the client library).

Closes #203
2020-09-11 11:10:24 -07:00
Mike Edmunds
bc1156149a Mailjet: Upgrade to Send API v3.1 [breaking]
Switch from Mailjet's older v3.0 Send API to the newer v3.1 version.

This is a breaking change for code using the Mailjet backend and:
* Using `esp_extra`, which must be updated to the new API format
* Using multiple `reply_to` addresses, which the v3.1 API doesn't allow

Closes #81
2020-09-08 14:50:26 -07:00
Mike Edmunds
85cec5e9dc Drop Python 2 and Django 1.11 support
Minimum supported versions are now Django 2.0, Python 3.5.

This touches a lot of code, to:
* Remove obsolete portability code and workarounds
  (six, backports of email parsers, test utils, etc.)
* Use Python 3 syntax (class defs, raise ... from, etc.)
* Correct inheritance for mixin classes
* Fix outdated docs content and links
* Suppress Python 3 "unclosed SSLSocket" ResourceWarnings
  that are beyond our control (in integration tests due to boto3, 
  python-sparkpost)
2020-08-01 14:53:10 -07:00
medmunds
c4ed6660b3 Mailjet: fix TypeError in sanitize_address
Fix TypeError when sending to or from addresses with
display names containing commas. Rewrite Anymail's
workaround for Mailjet's problem with commas in display
names, to avoid calling Django's internal sanitize_address
in an unsupported way.

The TypeError results from Django changes that will be
introduced in Django 2.2.15, 3.0.9, and 3.1.
2020-07-23 13:19:17 -07:00
medmunds
35792354b3 Amazon SES: fix bcc
Set SendRawEmail Destinations param to pick up all
recipients, including bcc (which doesn't appear in
message headers).

Fixes #189
2020-07-22 13:42:48 -07:00
jc-ee
2a36da54e6 Postmark: Fix sending templated email to a single recipient
Fix a bug where sending an email with a template_id and a single to address
would cause a Postmark API error.

Thanks @jc-ee for finding and fixing.
2020-04-13 13:48:37 -07:00
Mike Edmunds
920d8dd70f SendGrid: Fix multiple recipients with only merge_global_data
In SendGrid backend, support non-batch template send to multiple
recipients when `merge_global_data` is set without `merge_data`.
Regression introduced in v6.0.

Fixes #179
2020-03-18 17:08:10 -04:00
Mike Edmunds
0a8887913c SendinBlue: additional template/tags improvements
Additional changes related to SendinBlue improvements in #158:

* Support multiple tags in webhooks (closes #162)
* Remove additional outdated template code in backend
* Update integration tests
* Update docs and changelog; note breaking changes as discussed in #161
2019-09-04 15:45:08 -07:00
Mike Edmunds
fd558e904e Mailgun: disable non-ASCII attachment filename workaround when not needed
urllib3 v1.25 fixes non-ASCII filenames in multipart form data to be
RFC 5758 compliant by default, so our earlier workaround is no longer
needed. Disable the workaround if we detect that Requests is using a
fixed version of urllib3.

Closes #157
2019-09-03 18:04:27 -07:00
Mike Edmunds
df29ee2da6 Mailgun: make merge_data work with stored handlebars templates
Mailgun has two different template mechanisms and two different ways
of providing substitution variables to them. Update Anymail's
normalized merge_data handling to work with either (while preserving
existing batch send and metadata capabilities that also use Mailgun's
custom data and recipient variables parameters).

Completes work started by @anstosa in #156.
Closes #155.
2019-09-03 11:51:19 -07:00
Thorben Luepkes
989d56bd85 Sendinblue: use latest API improvements (templates, tags)
Track Sendinblue API updates:
* Multiple tags are now supported
* When using a template, display name is now supported on 'to', 'bcc', 'cc' and 'replyTo'
* Templates now support overriding 'from_email' and 'subject'
* Templates no longer require separate API endpoint
* 'merge_global_data' can be used without templates
2019-08-28 18:52:11 -07:00
Ansel Santosa
73a73ea01f Mailgun: Support stored templates
Add support for Mailgun's new template option

Fixes #155
2019-07-30 10:50:42 -07:00
medmunds
dabbdad3bd Properly encode path components used to construct API URLs
Resolves #144 and similar potential issues
2019-02-23 15:27:41 -08:00
medmunds
578bad9a57 SendGrid: generate unique message_id for each batch recipient
Closes #139
2019-02-23 15:01:54 -08:00
medmunds
d2d568b6d3 SendGrid: simplify personalizations processing; stop using "sections"
* Rework and simplify personalizations code (that had grown convoluted
  through several feature additions).

* Stop putting merge_global_data in legacy template "sections"; instead
  just merge it into individual personalization substitutions like we
  do for dynamic templates. (The "sections" version didn't add any
  functionality, had the potential for conflicts with the user's own
  template section tags, and was needlessly complex.)
2019-02-23 14:07:01 -08:00
Mike Edmunds
75d7671056 Add merge_metadata for other ESPs
Support merge_metadata in Mailgun, Mailjet, Mandrill, Postmark, 
SparkPost, and Test backends. (SendGrid covered in earlier PR.)

Also:
* Add `merge_metadata` to AnymailMessage, AnymailMessageMixin
* Add `is_batch()` logic to BasePayload, for consistent handling
* Docs

Note: Mailjet implementation switches *all* batch sending from their 
"Recipients" field to to the "Messages" array bulk sending option.
This allows an independent payload for each batch recipient.
In addition to supporting merge_metadata, this also removes the
prior limitation on mixing Cc/Bcc with merge_data.

Closes #141.
2019-02-23 13:32:28 -08:00
Janne Thoft
85dce5fd6a SendGrid: add merge_metadata
Add support in SendGrid backend for per-recipient metadata.
2019-02-21 12:44:53 -08:00
medmunds
412a1b78c6 Mailgun: Better error message for invalid sender domains
Try to catch cases where Mailgun will return HTTP 200-OK with the
text "Mailgun Magnificent API" rather than sending the email.

See #144.
2019-02-19 17:42:06 -08:00
medmunds
f64e98141a Postmark: don't error on Cc/Bcc-only send; preserve recipient caps
Postmark docs notwithstanding, Postmark allows sending mail without a
To field, as long as there is some recipient in Cc or Bcc. The API
response has a slightly different shape in this case, and Anymail now
handles that.

Also updates related recipient status parsing. Previously, Anymail's
Postmark backend converted all recipient emails to lowercase for status
reporting, and omitted Cc or Bcc recipients from
`message.anymail_status.recipients[email]`. Now, the backend preserves
the case of each recipient email as originally sent, and includes Cc
and Bcc status.

Because client code may have been relying on lowercasing recipient
emails to check status, this is a potentially breaking change.

Fixes #135
2019-02-05 11:08:26 -08:00
medmunds
10f6f3f821 Postmark: Support both TemplateAlias and TemplateId as template_id
Accept either Postmark's template alias or numeric id for `template_id`.
2018-11-06 18:39:49 -08:00
medmunds
2cf14c3653 Mailgun: raise unsupported feature error on attachment without filename.
Mailgun's API silently drops attachments without filenames (and inline
attachments without Content-IDs). Raise an AnymailUnsupportedFeature
error on attempts to send these attachments.

Fixes #128
2018-10-11 15:38:50 -07:00
medmunds
4028eda583 Fix Python 3.4
(%-interpolation for bytes isn't available until Python 3.5)
2018-10-10 16:50:07 -07:00
medmunds
3f63fdd713 Mailgun: Fix lost attachments with non-ASCII filenames.
Workaround requests/requests#4652 (urllib3/urllib3#303), where
uploaded files in multipart/form-data are improperly given RFC 2231
encoded filenames. That format is not accepted by Mailgun's API (and is
prohibited by RFC 7578), resulting in the attachments being silently
dropped.

Fix is to patch up the multipart/form-data before posting to remove
the RFC 2231 encoding.

Fixes #125
2018-10-10 15:02:13 -07:00
medmunds
ddafac9fbd Add DEBUG_API_REQUESTS Anymail setting to dump API communications.
Optionally dump API requests and responses to stdout, to simplify
debugging of the raw API communications. Currently implemented only
for Requests-based backends.

This (undocumented) setting can log things like API keys, so is not
appropriate for use in production.
2018-10-10 14:24:35 -07:00
medmunds
9c493dba72 Postmark: Support merge_data and batch sending.
Use Postmark /email/batch or /email/batchWithTemplates APIs when
merge_data provided.

Parse Postmark batch-send API responses, and improve accuracy of
parsing individual recipient status from all responses.

Closes #122
2018-09-06 17:24:04 -07:00
medmunds
753c895301 Postmark: Fix Postmark error on empty subject/body with template_id.
Postmark issues an error if Django's default empty strings are used
with template sends.

Include template send in Postmark integration tests. (Requires real
Postmark API token -- templates aren't testable with Postmark's
sandbox token.)

Fixes #121
2018-09-05 12:41:33 -07:00
medmunds
cb521e0e0e Python 3.8 (prep): Import Mapping etc. from collections.abc
Python 3.3 moved various collections abstract base classes from
`collections` to `collections.abc`, but also kept them available in
`collections` for compatibility with Python 2. Python 3.8 will allow
importing only from `collections.abc`.

(`collections.abc` hasn't yet been added to six.moves; see
https://github.com/benjaminp/six/issues/155.)
2018-08-27 11:24:44 -07:00
medmunds
382ebf249c SendGrid: Improve esp_extra["personalizations"] handling.
Allow merging `esp_extra["personalizations"]` dict into other
message-derived personalizations.

(See comments in #120)
2018-08-27 11:10:48 -07:00
medmunds
dbca13243f SendGrid: support new "dynamic" transactional templates
Closes #120
2018-08-24 18:21:42 -07:00
medmunds
5212848dc3 Amazon SES: Work around SES bug that corrupts non-ASCII message bodies.
If you are using an SES ConfigurationSet with open or click tracking
enabled, SES replaces non-ASCII characters with question marks as it
rewrites the message to add tracking, if the bodies are sent with
`Content-Transfer-Encoding: 8bit` (which is Django's default for utf8
body parts).

Force potentially problematic parts to use CTE: quoted-printable
as a workaround.

Fixes #115.
2018-08-14 17:24:49 -07:00
medmunds
46ff2e859c Postmark: Add metadata support
Closes #114
2018-08-11 16:00:58 -07:00
medmunds
02e6daf9d4 SendGrid: drop deprecated sendgrid_v2 EmailBackend 2018-05-30 16:02:21 -07:00
medmunds
52a6d2d822 Tests: stop using sendgrid_v2 backend for settings tests 2018-05-30 16:00:49 -07:00
Josh Kersey
d8d1407c61 SendGrid: change message_id from Message-ID/smtp-id to UUID anymail_id
SendGrid does not always correctly provide the sent Message-ID header value 
to a tracking webhook's smtp-id field, making it unreliable to use for Anymail's 
`message_id`.

Instead, generate a UUID `message_id` for Anymail tracking, and pass it from 
send to webhooks in SendGrid custom args as anymail_id.

Webhooks will fall back to smtp-id for compatibility with previously-sent 
messages that didn't have an anymail_id custom arg.

Fixes #108
2018-05-30 11:52:36 -07:00
medmunds
5598c87e62 Backends: identify source of problem in AnymailInvalidAddress message
Include the name of the field with the the unparsable email address
in AnymailInvalidAddress error messages.

Should help tracking down problems like in #98.
2018-04-11 11:50:06 -07:00
Mike Edmunds
ef69fa3bf7 Amazon SES support
Integrate Amazon SES.

Closes #54.
2018-04-11 10:35:23 -07:00
medmunds
05f11db4ce SparkPost: add SPARKPOST_API_URL setting to allow SparkPost EU, etc.
Closes #100
2018-04-06 12:58:58 -07:00
medmunds
b72e0b0274 Internal: Hoist RequestsPayload.serialize_json to BasePayload
(Non-Requests payloads sometimes want to serialize json, too.)
2018-03-24 10:09:46 -07:00