mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 11:51:05 -05:00
Handle bcc as Mandrill bcc_address, rather than additional to address
This commit is contained in:
15
README.rst
15
README.rst
@@ -138,11 +138,16 @@ Djrill supports most of the functionality of Django's `EmailMessage`_ and
|
|||||||
"image/\*", or "application/pdf" (since that is all Mandrill allows). Any
|
"image/\*", or "application/pdf" (since that is all Mandrill allows). Any
|
||||||
other attachment types will raise a ``djrill.NotSupportedByMandrillError``
|
other attachment types will raise a ``djrill.NotSupportedByMandrillError``
|
||||||
exception when you attempt to send the message.
|
exception when you attempt to send the message.
|
||||||
* Djrill treats all cc and bcc recipients as if they were additional "to"
|
* Djrill treats all "cc" recipients as if they were additional "to" addresses.
|
||||||
addresses. (Mandrill does not distinguish cc, and only allows a single bcc --
|
(Mandrill does not distinguish "cc" from "to".) Note that you will also need
|
||||||
which Djrill doesn't use. *Caution:* depending on the ``preserve_recipients``
|
to set ``preserve_recipients`` True if you want each recipient to see the
|
||||||
setting, this could result in exposing bcc addresses to all recipients. It's
|
other recipients listed in the email headers.
|
||||||
probably best to just avoid bcc.)
|
* Mandrill does not permit more than one "bcc" address. Djrill raises
|
||||||
|
``djrill.NotSupportedByMandrillError`` if you attempt to send a message with
|
||||||
|
multiple bcc's. (Mandrill's bcc option seems intended primarily for logging.
|
||||||
|
To send a single message to multiple recipients without exposing their
|
||||||
|
email addresses to each other, simply include them all in the "to" list and
|
||||||
|
leave ``preserve_recipients`` set to False.)
|
||||||
* All email addresses (from, to, cc) can be simple ("email@example.com") or
|
* All email addresses (from, to, cc) can be simple ("email@example.com") or
|
||||||
can include a display name ("Real Name <email@example.com>").
|
can include a display name ("Real Name <email@example.com>").
|
||||||
* The ``from_email`` must be in one of the approved sending domains in your
|
* The ``from_email`` must be in one of the approved sending domains in your
|
||||||
|
|||||||
@@ -105,10 +105,11 @@ class DjrillBackend(BaseEmailBackend):
|
|||||||
sender = sanitize_address(message.from_email, message.encoding)
|
sender = sanitize_address(message.from_email, message.encoding)
|
||||||
from_name, from_email = parseaddr(sender)
|
from_name, from_email = parseaddr(sender)
|
||||||
|
|
||||||
recipients = [parseaddr(sanitize_address(addr, message.encoding))
|
recipients = message.to + message.cc # message.recipients() w/o bcc
|
||||||
for addr in message.recipients()]
|
parsed_rcpts = [parseaddr(sanitize_address(addr, message.encoding))
|
||||||
|
for addr in recipients]
|
||||||
to_list = [{"email": to_email, "name": to_name}
|
to_list = [{"email": to_email, "name": to_name}
|
||||||
for (to_name, to_email) in recipients]
|
for (to_name, to_email) in parsed_rcpts]
|
||||||
|
|
||||||
msg_dict = {
|
msg_dict = {
|
||||||
"text": message.body,
|
"text": message.body,
|
||||||
@@ -119,6 +120,15 @@ class DjrillBackend(BaseEmailBackend):
|
|||||||
if from_name:
|
if from_name:
|
||||||
msg_dict["from_name"] = from_name
|
msg_dict["from_name"] = from_name
|
||||||
|
|
||||||
|
if len(message.bcc) == 1:
|
||||||
|
bcc = message.bcc[0]
|
||||||
|
_, bcc_addr = parseaddr(sanitize_address(bcc, message.encoding))
|
||||||
|
msg_dict['bcc_address'] = bcc_addr
|
||||||
|
elif len(message.bcc) > 1:
|
||||||
|
raise NotSupportedByMandrillError(
|
||||||
|
"Too many bcc addresses (%d) - Mandrill only allows one"
|
||||||
|
% len(message.bcc))
|
||||||
|
|
||||||
if message.extra_headers:
|
if message.extra_headers:
|
||||||
for k in message.extra_headers.keys():
|
for k in message.extra_headers.keys():
|
||||||
if k != "Reply-To" and not k.startswith("X-"):
|
if k != "Reply-To" and not k.startswith("X-"):
|
||||||
|
|||||||
@@ -35,22 +35,32 @@ class DjrillBackendTests(DjrillBackendMockAPITestCase):
|
|||||||
|
|
||||||
(Test both sender and recipient addresses)
|
(Test both sender and recipient addresses)
|
||||||
"""
|
"""
|
||||||
mail.send_mail('Subject', 'Message', 'From Name <from@example.com>',
|
msg = mail.EmailMessage('Subject', 'Message',
|
||||||
['Recipient #1 <to1@example.com>', 'to2@example.com'])
|
'From Name <from@example.com>',
|
||||||
|
['Recipient #1 <to1@example.com>', 'to2@example.com'],
|
||||||
|
cc=['Carbon Copy <cc1@example.com>', 'cc2@example.com'],
|
||||||
|
bcc=['Blind Copy <bcc@example.com>'])
|
||||||
|
msg.send()
|
||||||
data = self.get_api_call_data()
|
data = self.get_api_call_data()
|
||||||
self.assertEqual(data['message']['from_name'], "From Name")
|
self.assertEqual(data['message']['from_name'], "From Name")
|
||||||
self.assertEqual(data['message']['from_email'], "from@example.com")
|
self.assertEqual(data['message']['from_email'], "from@example.com")
|
||||||
self.assertEqual(len(data['message']['to']), 2)
|
self.assertEqual(len(data['message']['to']), 4)
|
||||||
self.assertEqual(data['message']['to'][0]['name'], "Recipient #1")
|
self.assertEqual(data['message']['to'][0]['name'], "Recipient #1")
|
||||||
self.assertEqual(data['message']['to'][0]['email'], "to1@example.com")
|
self.assertEqual(data['message']['to'][0]['email'], "to1@example.com")
|
||||||
self.assertEqual(data['message']['to'][1]['name'], "")
|
self.assertEqual(data['message']['to'][1]['name'], "")
|
||||||
self.assertEqual(data['message']['to'][1]['email'], "to2@example.com")
|
self.assertEqual(data['message']['to'][1]['email'], "to2@example.com")
|
||||||
|
self.assertEqual(data['message']['to'][2]['name'], "Carbon Copy")
|
||||||
|
self.assertEqual(data['message']['to'][2]['email'], "cc1@example.com")
|
||||||
|
self.assertEqual(data['message']['to'][3]['name'], "")
|
||||||
|
self.assertEqual(data['message']['to'][3]['email'], "cc2@example.com")
|
||||||
|
# Mandrill only supports email, not name, for bcc:
|
||||||
|
self.assertEqual(data['message']['bcc_address'], "bcc@example.com")
|
||||||
|
|
||||||
def test_email_message(self):
|
def test_email_message(self):
|
||||||
email = mail.EmailMessage('Subject', 'Body goes here',
|
email = mail.EmailMessage('Subject', 'Body goes here',
|
||||||
'from@example.com',
|
'from@example.com',
|
||||||
['to1@example.com', 'Also To <to2@example.com>'],
|
['to1@example.com', 'Also To <to2@example.com>'],
|
||||||
bcc=['bcc1@example.com', 'Also BCC <bcc2@example.com>'],
|
bcc=['bcc@example.com'],
|
||||||
cc=['cc1@example.com', 'Also CC <cc2@example.com>'],
|
cc=['cc1@example.com', 'Also CC <cc2@example.com>'],
|
||||||
headers={'Reply-To': 'another@example.com',
|
headers={'Reply-To': 'another@example.com',
|
||||||
'X-MyHeader': 'my value'})
|
'X-MyHeader': 'my value'})
|
||||||
@@ -62,16 +72,15 @@ class DjrillBackendTests(DjrillBackendMockAPITestCase):
|
|||||||
self.assertEqual(data['message']['from_email'], "from@example.com")
|
self.assertEqual(data['message']['from_email'], "from@example.com")
|
||||||
self.assertEqual(data['message']['headers'],
|
self.assertEqual(data['message']['headers'],
|
||||||
{ 'Reply-To': 'another@example.com', 'X-MyHeader': 'my value' })
|
{ 'Reply-To': 'another@example.com', 'X-MyHeader': 'my value' })
|
||||||
# Mandrill doesn't have a notion of cc, and only allows a single bcc.
|
# Mandrill doesn't have a notion of cc.
|
||||||
# Djrill just treats cc and bcc as though they were "to" addresses,
|
# Djrill just treats cc as additional "to" addresses,
|
||||||
# which may or may not be what you want.
|
# which may or may not be what you want.
|
||||||
self.assertEqual(len(data['message']['to']), 6)
|
self.assertEqual(len(data['message']['to']), 4)
|
||||||
self.assertEqual(data['message']['to'][0]['email'], "to1@example.com")
|
self.assertEqual(data['message']['to'][0]['email'], "to1@example.com")
|
||||||
self.assertEqual(data['message']['to'][1]['email'], "to2@example.com")
|
self.assertEqual(data['message']['to'][1]['email'], "to2@example.com")
|
||||||
self.assertEqual(data['message']['to'][2]['email'], "cc1@example.com")
|
self.assertEqual(data['message']['to'][2]['email'], "cc1@example.com")
|
||||||
self.assertEqual(data['message']['to'][3]['email'], "cc2@example.com")
|
self.assertEqual(data['message']['to'][3]['email'], "cc2@example.com")
|
||||||
self.assertEqual(data['message']['to'][4]['email'], "bcc1@example.com")
|
self.assertEqual(data['message']['bcc_address'], "bcc@example.com")
|
||||||
self.assertEqual(data['message']['to'][5]['email'], "bcc2@example.com")
|
|
||||||
|
|
||||||
def test_html_message(self):
|
def test_html_message(self):
|
||||||
text_content = 'This is an important message.'
|
text_content = 'This is an important message.'
|
||||||
@@ -178,6 +187,14 @@ class DjrillBackendTests(DjrillBackendMockAPITestCase):
|
|||||||
mimetype="application/vnd.ms-powerpoint")
|
mimetype="application/vnd.ms-powerpoint")
|
||||||
msg.send()
|
msg.send()
|
||||||
|
|
||||||
|
def test_bcc_errors(self):
|
||||||
|
# Mandrill only allows a single bcc address
|
||||||
|
with self.assertRaises(NotSupportedByMandrillError):
|
||||||
|
msg = mail.EmailMessage('Subject', 'Body',
|
||||||
|
'from@example.com', ['to@example.com'],
|
||||||
|
bcc=['bcc1@example.com>', 'bcc2@example.com'])
|
||||||
|
msg.send()
|
||||||
|
|
||||||
def test_mandrill_api_failure(self):
|
def test_mandrill_api_failure(self):
|
||||||
self.mock_post.return_value = self.MockResponse(status_code=400)
|
self.mock_post.return_value = self.MockResponse(status_code=400)
|
||||||
with self.assertRaises(MandrillAPIError):
|
with self.assertRaises(MandrillAPIError):
|
||||||
@@ -295,6 +312,7 @@ class DjrillMandrillFeatureTests(DjrillBackendMockAPITestCase):
|
|||||||
self.assert_mandrill_called("/messages/send.json")
|
self.assert_mandrill_called("/messages/send.json")
|
||||||
data = self.get_api_call_data()
|
data = self.get_api_call_data()
|
||||||
self.assertFalse('from_name' in data['message'])
|
self.assertFalse('from_name' in data['message'])
|
||||||
|
self.assertFalse('bcc_address' in data['message'])
|
||||||
self.assertFalse('track_opens' in data['message'])
|
self.assertFalse('track_opens' in data['message'])
|
||||||
self.assertFalse('track_clicks' in data['message'])
|
self.assertFalse('track_clicks' in data['message'])
|
||||||
self.assertFalse('auto_text' in data['message'])
|
self.assertFalse('auto_text' in data['message'])
|
||||||
|
|||||||
Reference in New Issue
Block a user