Commit Graph

20 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
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
bd9d92f5a0 Cleanup: centralize Reply-To header handling; case-insensitive headers
Django allows setting the reply address with either message.reply_to
or message.extra_headers["Reply-To"]. If both are supplied, the extra
headers version takes precedence. (See EmailMessage.message().)

Several Anymail backends had duplicate logic to handle conflicting
properties. Move that logic into the base Payload.

(Also prepares for common handling of extra_headers['From'], later.)

Related changes:

* Use CaseInsensitiveDict for processing extra_headers.
  This is potentially a breaking change, but any code that was trying
  to send multiple headers differing only in case was likely already
  broken. (Email header field names are case-insensitive, per RFC-822.)

* Handle CaseInsensitiveDict in RequestsPayload.serialize_json().
  (Several backends had duplicate code for handling this, too.)

* Fixes SparkPost backend, which had been incorrectly treating
  message.reply_to and message.extra_headers['Reply-To'] differently.
2018-02-26 12:25:57 -08:00
medmunds
9acf6501b5 Utils: Finish ParsedEmail --> EmailAddress conversion
Within an EmailAddress (previously ParsedEmail object), properties
now match Python 3.6 email.headerregistry.Address naming:

* .email --> .addr_spec
* .name --> .display_name
* .localpart --> .username

(Completes work started in 386668908423d1d4eade90cf7a21a546a1e96514;
this updates remaining uses of old names and removes them.)
2017-10-27 17:53:13 -07: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
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
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
df881fdb75 Allow kwargs overrides for (nearly) all 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
2016-04-29 14:34:34 -07:00
medmunds
34d6676afa Add Postmark support 2016-03-14 11:06:45 -07:00