From 2395d4c96c6f412e26b5cdc166de2f0572b578a6 Mon Sep 17 00:00:00 2001 From: John Calhoun Date: Mon, 20 Jul 2020 07:31:16 -0700 Subject: [PATCH 1/2] remove duplicate emails ignoring case in Personalization --- sendgrid/helpers/mail/personalization.py | 32 +++- test/test_mail_helpers.py | 182 +++++++++++++++++++++++ 2 files changed, 211 insertions(+), 3 deletions(-) diff --git a/sendgrid/helpers/mail/personalization.py b/sendgrid/helpers/mail/personalization.py index 9239f9458..b2b71ba51 100644 --- a/sendgrid/helpers/mail/personalization.py +++ b/sendgrid/helpers/mail/personalization.py @@ -19,14 +19,31 @@ def add_email(self, email): email_type = type(email) if email_type.__name__ == 'To': self.add_to(email) + self._tos = self._get_unique_recipients(self._tos) return if email_type.__name__ == 'Cc': self.add_cc(email) + self._ccs = self._get_unique_recipients(self._ccs) return if email_type.__name__ == 'Bcc': self.add_bcc(email) + self._bccs = self._get_unique_recipients(self._bccs) return raise ValueError('Please use a To, Cc or Bcc object.') + + def _get_unique_recipients(self, recipients): + unique_recipients = [] + + for recipient in recipients: + recipient_email = recipient['email'].lower() if isinstance(recipient, dict) else recipient.email.lower() + if all( + unique_recipient['email'].lower() != recipient_email for unique_recipient in unique_recipients + ): + new_unique_recipient = recipient if isinstance(recipient, dict) else recipient.get() + unique_recipients.append(new_unique_recipient) + + return unique_recipients + @property def tos(self): @@ -38,7 +55,10 @@ def tos(self): @tos.setter def tos(self, value): - self._tos = value + if isinstance(value, list): + self._tos = self._get_unique_recipients(value) + else: + self._tos = value def add_to(self, email): """Add a single recipient to this Personalization. @@ -73,7 +93,10 @@ def ccs(self): @ccs.setter def ccs(self, value): - self._ccs = value + if isinstance(value, list): + self._ccs = self._get_unique_recipients(value) + else: + self._ccs = value def add_cc(self, email): """Add a single recipient to receive a copy of this email. @@ -93,7 +116,10 @@ def bccs(self): @bccs.setter def bccs(self, value): - self._bccs = value + if isinstance(value, list): + self._bccs = self._get_unique_recipients(value) + else: + self._bccs = value def add_bcc(self, email): """Add a single recipient to receive a blind carbon copy of this email. diff --git a/test/test_mail_helpers.py b/test/test_mail_helpers.py index 202d3948b..8caf805cf 100644 --- a/test/test_mail_helpers.py +++ b/test/test_mail_helpers.py @@ -379,6 +379,188 @@ def test_error_is_not_raised_on_to_emails_includes_bcc_cc(self): html_content=HtmlContent( 'and easy to do anywhere, even with Python')) + def test_personalization_add_email_filters_out_duplicate_to_emails(self): + self.maxDiff = None + + p = Personalization() + to_email = To('test+to0@example.com', 'Example To Name 0') + p.add_email(to_email) + p.add_email(to_email) + + self.assertEqual([to_email.get()], p.tos) + + def test_personalization_add_email_filters_out_duplicate_to_emails_ignoring_case(self): + self.maxDiff = None + + p = Personalization() + to_email = To('test+to0@example.com', 'Example To Name 0') + to_email_with_caps = To('test+TO0@example.com', 'Example To Name 0') + p.add_email(to_email) + p.add_email(to_email_with_caps) + + self.assertEqual([to_email.get()], p.tos) + + def test_personalization_filters_out_duplicate_cc_emails(self): + self.maxDiff = None + + p = Personalization() + cc_email = Cc('test+cc0@example.com', 'Example Cc Name 0') + p.add_email(cc_email) + p.add_email(cc_email) + + self.assertEqual([cc_email.get()], p.ccs) + + def test_personalization_filters_out_duplicate_cc_emails_ignoring_case(self): + self.maxDiff = None + + p = Personalization() + cc_email = Cc('test+cc0@example.com', 'Example Cc Name 0') + cc_email_with_caps = Cc('test+CC0@example.com', 'Example Cc Name 0') + p.add_email(cc_email) + p.add_email(cc_email_with_caps) + + self.assertEqual([cc_email.get()], p.ccs) + + def test_personalization_filters_out_duplicate_bcc_emails(self): + self.maxDiff = None + + p = Personalization() + bcc_email = Bcc('test+bcc0@example.com', 'Example Bcc Name 0') + p.add_email(bcc_email) + p.add_email(bcc_email) + + self.assertEqual([bcc_email.get()], p.bccs) + + def test_personalization_filters_out_duplicate_bcc_emails_ignoring_case(self): + self.maxDiff = None + + p = Personalization() + bcc_email = Bcc('test+bcc0@example.com', 'Example Bcc Name 0') + bcc_email_with_caps = Bcc('test+BCC0@example.com', 'Example Bcc Name 0') + p.add_email(bcc_email) + p.add_email(bcc_email_with_caps) + + self.assertEqual([bcc_email.get()], p.bccs) + + def test_personalization_tos_setter_filters_out_duplicate_dict_emails(self): + self.maxDiff = None + + p = Personalization() + to_emails = [{ 'email': 'test+to0@example.com', 'name': 'Example To Name 0' }] * 2 + p.tos = to_emails + + self.assertEqual([to_emails[0]], p.tos) + + def test_personalization_tos_setter_filters_out_duplicate_dict_emails_ignoring_case(self): + self.maxDiff = None + + p = Personalization() + to_email = { 'email': 'test+to0@example.com', 'name': 'Example To Name 0' } + to_email_with_caps = { 'email': 'test+TO0@example.com', 'name': 'Example To Name 0' } + to_emails = [to_email, to_email_with_caps] + p.tos = to_emails + + self.assertEqual([to_email], p.tos) + + def test_personalization_tos_setter_filters_out_duplicate_to_emails(self): + self.maxDiff = None + + p = Personalization() + to_emails = [To('test+to0@example.com', 'Example To Name 0')] * 2 + p.tos = to_emails + + self.assertEqual([to_emails[0].get()], p.tos) + + + def test_personalization_tos_setter_filters_out_duplicate_to_emails_ignoring_case(self): + self.maxDiff = None + + p = Personalization() + to_email = To('test+to0@example.com', 'Example To Name 0') + to_email_with_caps = To('test+TO0@example.com', 'Example To Name 0') + to_emails = [to_email, to_email_with_caps] + p.tos = to_emails + + self.assertEqual([to_email.get()], p.tos) + + def test_personalization_ccs_setter_filters_out_duplicate_dict_emails(self): + self.maxDiff = None + + p = Personalization() + cc_emails = [{ 'email': 'test+cc0@example.com', 'name': 'Example Cc Name 0' }] * 2 + p.ccs = cc_emails + + self.assertEqual([cc_emails[0]], p.ccs) + + def test_personalization_ccs_setter_filters_out_duplicate_dict_emails_ignoring_case(self): + self.maxDiff = None + + p = Personalization() + cc_email = { 'email': 'test+cc0@example.com', 'name': 'Example Cc Name 0' } + cc_email_with_caps = { 'email': 'test+CC0@example.com', 'name': 'Example Cc Name 0' } + cc_emails = [cc_email, cc_email_with_caps] + p.ccs = cc_emails + + self.assertEqual([cc_email], p.ccs) + + def test_personalization_ccs_setter_filters_out_duplicate_cc_emails(self): + self.maxDiff = None + + p = Personalization() + cc_emails = [Cc('test+cc0@example.com', 'Example Cc Name 0')] * 2 + p.ccs = cc_emails + + self.assertEqual([cc_emails[0].get()], p.ccs) + + def test_personalization_ccs_setter_filters_out_duplicate_cc_emails_ignoring_case(self): + self.maxDiff = None + + p = Personalization() + cc_email = Cc('test+cc0@example.com', 'Example Cc Name 0') + cc_email_with_caps = Cc('test+CC0@example.com', 'Example Cc Name 0') + p.ccs = [cc_email, cc_email_with_caps] + + self.assertEqual([cc_email.get()], p.ccs) + + def test_personalization_bccs_setter_filters_out_duplicate_dict_emails(self): + self.maxDiff = None + + p = Personalization() + bcc_emails = [{ 'email': 'test+bcc0@example.com', 'name': 'Example Bcc Name 0' }] * 2 + p.bccs = bcc_emails + + self.assertEqual([bcc_emails[0]], p.bccs) + + def test_personalization_bccs_setter_filters_out_duplicate_dict_emails_ignoring_case(self): + self.maxDiff = None + + p = Personalization() + bcc_email = { 'email': 'test+bcc0@example.com', 'name': 'Example Bcc Name 0' } + bcc_email_with_caps = { 'email': 'test+BCC0@example.com', 'name': 'Example Bcc Name 0' } + bcc_emails = [bcc_email, bcc_email_with_caps] + p.bccs = bcc_emails + + self.assertEqual([bcc_email], p.bccs) + + def test_personalization_bccs_setter_filters_out_duplicate_bcc_emails(self): + self.maxDiff = None + + p = Personalization() + bcc_emails = [Bcc('test+bcc0@example.com', 'Example Bcc Name 0')] * 2 + p.bccs = bcc_emails + + self.assertEqual([bcc_emails[0].get()], p.bccs) + + def test_personalization_bccs_setter_filters_out_duplicate_bcc_emails_ignoring_case(self): + self.maxDiff = None + + p = Personalization() + bcc_email = Bcc('test+bcc0@example.com', 'Example Bcc Name 0') + bcc_email_with_caps = Bcc('test+BCC0@example.com', 'Example Bcc Name 0') + p.bccs = [bcc_email, bcc_email_with_caps] + + self.assertEqual([bcc_email.get()], p.bccs) + def test_dynamic_template_data(self): self.maxDiff = None From 2eb393dc20be953cc9868dfb37a6ae827fb79b68 Mon Sep 17 00:00:00 2001 From: John Calhoun Date: Mon, 21 Dec 2020 08:08:47 -0800 Subject: [PATCH 2/2] filtered getters instead of setters --- sendgrid/helpers/mail/personalization.py | 24 ++++------------ test/test_mail_helpers.py | 36 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/sendgrid/helpers/mail/personalization.py b/sendgrid/helpers/mail/personalization.py index b2b71ba51..21a31c863 100644 --- a/sendgrid/helpers/mail/personalization.py +++ b/sendgrid/helpers/mail/personalization.py @@ -19,15 +19,12 @@ def add_email(self, email): email_type = type(email) if email_type.__name__ == 'To': self.add_to(email) - self._tos = self._get_unique_recipients(self._tos) return if email_type.__name__ == 'Cc': self.add_cc(email) - self._ccs = self._get_unique_recipients(self._ccs) return if email_type.__name__ == 'Bcc': self.add_bcc(email) - self._bccs = self._get_unique_recipients(self._bccs) return raise ValueError('Please use a To, Cc or Bcc object.') @@ -51,14 +48,11 @@ def tos(self): :rtype: list(dict) """ - return self._tos + return self._get_unique_recipients(self._tos) @tos.setter def tos(self, value): - if isinstance(value, list): - self._tos = self._get_unique_recipients(value) - else: - self._tos = value + self._tos = value def add_to(self, email): """Add a single recipient to this Personalization. @@ -89,14 +83,11 @@ def ccs(self): :rtype: list(dict) """ - return self._ccs + return self._get_unique_recipients(self._ccs) @ccs.setter def ccs(self, value): - if isinstance(value, list): - self._ccs = self._get_unique_recipients(value) - else: - self._ccs = value + self._ccs = value def add_cc(self, email): """Add a single recipient to receive a copy of this email. @@ -112,14 +103,11 @@ def bccs(self): :rtype: list(dict) """ - return self._bccs + return self._get_unique_recipients(self._bccs) @bccs.setter def bccs(self, value): - if isinstance(value, list): - self._bccs = self._get_unique_recipients(value) - else: - self._bccs = value + self._bccs = value def add_bcc(self, email): """Add a single recipient to receive a blind carbon copy of this email. diff --git a/test/test_mail_helpers.py b/test/test_mail_helpers.py index 8caf805cf..7e52be1e9 100644 --- a/test/test_mail_helpers.py +++ b/test/test_mail_helpers.py @@ -561,6 +561,42 @@ def test_personalization_bccs_setter_filters_out_duplicate_bcc_emails_ignoring_c self.assertEqual([bcc_email.get()], p.bccs) + def test_personalization_add_to_filters_out_duplicate_to_emails(self): + self.maxDiff = None + + p = Personalization() + to_email = To('test+to0@example.com', 'Example To Name 0') + p.add_to(to_email) + p.add_to(to_email) + + expected = [to_email.get()] + + self.assertEqual(expected, p.tos) + + def test_personalization_add_bcc_filters_out_duplicate_bcc_emails(self): + self.maxDiff = None + + p = Personalization() + bcc_email = Bcc('test+to0@example.com', 'Example To Name 0') + p.add_bcc(bcc_email) + p.add_bcc(bcc_email) + + expected = [bcc_email.get()] + + self.assertEqual(expected, p.bccs) + + def test_personalization_add_cc_filters_out_duplicate_cc_emails(self): + self.maxDiff = None + + p = Personalization() + cc_email = Cc('test+to0@example.com', 'Example To Name 0') + p.add_cc(cc_email) + p.add_cc(cc_email) + + expected = [cc_email.get()] + + self.assertEqual(expected, p.ccs) + def test_dynamic_template_data(self): self.maxDiff = None