Commit Graph

24 Commits

Author SHA1 Message Date
medmunds
9ed5ce0213 Postmark: Fix API error with template but no merge data
Fixes #223
2021-02-22 17:50:46 -08: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
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
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
Mike Edmunds
978996d7b8 Test without optional packages
Tox:
* Add Tox factor for extras (all, none, individual ESP).
  For now, only break out ESPs that have specific extra
  dependencies (amazon_ses, sparkpost).
* Install most package dependencies (including extras)
  through the package itself.
* Use new runtests.py environment vars to limit test tags
  when Tox isn't installing all extras.

Travis:
* Rework matrix to request specific TOXENVs directly;
  drop tox-travis.

Test runner (runtests.py):
* Centralize RUN_LIVE_TESTS logic in runtests.py
* Add ANYMAIL_ONLY_TEST and ANYMAIL_SKIP_TESTS env vars
  (comma-separated lists of tags)

Test implementations:
* Tag all ESP-specific tests with ESP
* Tag live tests with "live"
* Don't import ESP-specific packages at test module level. 
  (Test discovery imports test modules before tag-based filtering.)

Closes #104
2019-02-09 15:04:08 -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
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
46ff2e859c Postmark: Add metadata support
Closes #114
2018-08-11 16:00:58 -07:00
medmunds
07fbeac6bd Feature: Add envelope_sender
New EmailMessage attribute `envelope_sender` controls ESP's sender,
sending domain, or return path where supported:

* Mailgun: overrides SENDER_DOMAIN on individual message
  (domain portion only)
* Mailjet: becomes `Sender` API param
* Mandrill: becomes `return_path_domain` API param
  (domain portion only)
* SparkPost: becomes `return_path` API param
* Other ESPs: not believed to be supported

Also support undocumented Django SMTP backend behavior, where envelope
sender is given by `message.from_email` when
`message.extra_headers["From"]` is set. Fixes #91.
2018-02-26 18:42:19 -08:00
medmunds
a67e174f38 Remove deprecated <ESP>Backend names
(Deprecated with warnings since v0.8)
2017-09-08 16:42:28 -07:00
medmunds
6b6793016e Mailgun, SparkPost: support multiple from_email addresses
[RFC-5322 allows](https://tools.ietf.org/html/rfc5322#section-3.6.2)
multiple addresses in the From header.

Django's SMTP backend supports this, as a single comma-separated
string (*not* a list of strings like the recipient params):

    from_email='one@example.com, two@example.com'
    to=['one@example.com', 'two@example.com']

Both Mailgun and SparkPost support multiple From addresses
(and Postmark accepts them, though truncates to the first one
on their end). For compatibility with Django -- and because
Anymail attempts to support all ESP features -- Anymail now
allows multiple From addresses, too, for ESPs that support it.

Note: as a practical matter, deliverability with multiple
From addresses is pretty bad. (Google outright rejects them.)

This change also reworks Anymail's internal ParsedEmail object,
and approach to parsing addresses, for better consistency with
Django's SMTP backend and improved error messaging.

In particular, Django (and now Anymail) allows multiple email
addresses in a single recipient string:

    to=['one@example.com', 'two@example.com, three@example.com']
    len(to) == 2  # but there will be three recipients

Fixes #60
2017-04-19 12:43:33 -07:00
medmunds
23800657b8 Support Python 3.6 with Django 1.11-alpha
Only real problem is in json serialization tests:
Python 3.6 [changed][1] the json serialization
error message to use the object's class name
rather than its repr. E.g.:
  "Decimal('19.99') is not JSON serializable"
becomes:
  "Object of type 'Decimal' is not JSON serializable"

Update tests that looked for specific serialization
error message to just look for the word "Decimal"
instead. (Works with all Python versions.)

[1]: https://bugs.python.org/issue26623
2017-01-22 11:34:57 -08:00
medmunds
56d2b53c2b Use specific ESP name in error messages.
Change  (e.g.,) "ESP API response 400"
to "Mailgun API response 400".
2017-01-22 10:21:19 -08:00
medmunds
79288603fb Rename EmailBackends for Django consistency
* **Future breaking change:**
  Rename all Anymail backends to just `EmailBackend`,
  matching Django's naming convention.
  (E.g., switch to "anymail.backends.mailgun.EmailBackend"
  rather than "anymail.backends.mailgun.MailgunBackend".)

  The old names still work, but will issue a DeprecationWarning
  and will be removed in some future release.

  (Apologies for this change; the old naming convention was
  a holdover from Djrill, and I wanted consistency with
  other Django EmailBackends before hitting 1.0.)

Fixes #49.
2017-01-20 15:47:37 -08:00
medmunds
4ca39a976f Postmark: handle Reply-To in EmailMessage headers
Move 'Reply-To' header into dedicated Postmark API param

Fixes #39
2016-11-01 12:12:21 -07:00
medmunds
7248c3441e Postmark: add track_clicks support
Closes #38
2016-10-23 10:54:59 -07:00
medmunds
771ed513b2 Tests: switch to explicit u"unicode" literals
Drop `from __future__ import unicode_literals`;
it was there for Python 3.2 compatibility (which
Anymail doesn't support). Ensures tests use normal
strs in Python 2.x.
2016-10-13 14:37:08 -07:00
Adam Chainz
731670427c Tests: Convert readthedocs links to .io
Convert readthedocs links for their .org -> .io migration for hosted projects

As per [their blog post of the 27th April](https://blog.readthedocs.com/securing-subdomains/) ‘Securing subdomains’:

> Starting today, Read the Docs will start hosting projects from subdomains on the domain readthedocs.io, instead of on readthedocs.org. This change addresses some security concerns around site cookies while hosting user generated data on the same domain as our dashboard.

Test Plan: Manually visited all the links I’ve modified.
2016-06-22 14:57:58 -07:00
medmunds
c60790fb52 Use generic TestBackend for base functionality tests
* Create generic TestBackend that simply collects
  send parameters
* Change BackendSettingsTests to TestBackend,
  and add some missing cases
* Add UnsupportedFeatureTests
* Replace repetitive per-backend SEND_DEFAULTS
  test cases with single (and more comprehensive)
  SendDefaultsTests
2016-05-12 17:18:48 -07:00
medmunds
75730e8219 Add ESP templates, batch send and merge
* 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.
2016-05-06 12:27:11 -07:00
medmunds
c7a8c81e32 Remove pre-Django 1.8 compatibility code 2016-04-30 10:33:51 -07:00
medmunds
385d76b53a Move tests out of app module
(Directory structure as suggested in
[Django testing docs][1].)

[1]: https://docs.djangoproject.com/en/1.9/topics/testing/advanced/#using-the-django-test-runner-to-test-reusable-applications
2016-03-21 11:38:58 -07:00