def test_init_no_setting(self): # Tests that SENDGRID_API_KEY must be set for the SendgridBackend to initialize. # (or an api key must be explicitly passed to the constructor) backend = SendgridBackend(api_key="DUMMY_API_KEY") with self.assertRaises(ImproperlyConfigured): backend = SendgridBackend() # noqa
def setUpClass(self): super(TestMailGeneration, self).setUpClass() with override_settings( EMAIL_BACKEND="sendgrid_backend.SendgridBackend", SENDGRID_API_KEY="DUMMY_API_KEY", ): self.backend = SendgridBackend()
def contact_index(request): if request.method == 'GET': form = ContactForm() else: form = ContactForm(request.POST) if form.is_valid(): template = get_template('contact_template.txt') name = form.cleaned_data['name'] from_email = form.cleaned_data['from_email'] message = form.cleaned_data['message'] context = { 'name': name, 'from_email': from_email, 'message': message, } content = template.render(context) html_thanks = render_to_string("email.html", context) try: request_email = EmailMessage( name + ' - Customer Contact Request', content, 'Your Website<*****@*****.**>', ['*****@*****.**'], reply_to=[from_email]) thanks_email = EmailMessage( 'DO NOT REPLY - Senior Technology Associates', html_thanks, '*****@*****.**', [from_email]) thanks_email.content_subtype = 'html' sg = SendgridBackend() sg.send_messages([request_email, thanks_email]) messages.success( request, 'Message Recieved: Senior Technology Associates will get back to you ASAP' ) except BadHeaderError: return HttpResponse('Invalid header found.') return redirect('home_index') messages.info( request, 'Please pardon our appearance, this page is under construction.') recent_posts = Post.objects.all().order_by('-created_on')[:3] bios = Biography.objects.all() return render(request, "contact_index.html", { 'form': form, 'recent_posts': recent_posts, 'bios': bios, })
def test_echo(self): settings = { "DEBUG": True, "SENDGRID_API_KEY": "DOESNT_MATTER", "EMAIL_BACKEND": "sendgrid_backend.SendgridBackend", "SENDGRID_ECHO_TO_STDOUT": True, } with override_settings(**settings): mocked_output_stream = MagicMock() connection = SendgridBackend(stream=mocked_output_stream) msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>"], connection=connection, ) try: msg.send() except UnauthorizedError: # Since Github only runs live server tests on protected branches (for security), # we will get an unauthorized error when attempting to hit the sendgrid api endpoint, even in # sandbox mode. warnings.warn( "Sendgrid requests using sandbox mode still need valid credentials for the " + "request to succeed." ) self.assertTrue(mocked_output_stream.write.called)
def test_echo(self): settings = { "DEBUG": True, "SENDGRID_API_KEY": os.environ["SENDGRID_API_KEY"], "EMAIL_BACKEND": "sendgrid_backend.SendgridBackend", "SENDGRID_ECHO_TO_STDOUT": True } with override_settings(**settings): mocked_output_stream = MagicMock() connection = SendgridBackend(stream=mocked_output_stream) msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>"], connection=connection, ) msg.send() self.assertTrue(mocked_output_stream.write.called)
def test_sandbox_mode(self): msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>"], ) with override_settings(DEBUG=False, SENDGRID_SANDBOX_MODE_IN_DEBUG=True): backend = SendgridBackend(api_key="stub") result = backend._build_sg_mail(msg) self.assertIn("mail_settings", result) self.assertIn("sandbox_mode", result["mail_settings"]) self.assertFalse(result["mail_settings"]["sandbox_mode"]["enable"]) with override_settings(DEBUG=True, SENDGRID_SANDBOX_MODE_IN_DEBUG=True): backend = SendgridBackend(api_key="stub") result = backend._build_sg_mail(msg) self.assertIn("mail_settings", result) self.assertIn("sandbox_mode", result["mail_settings"]) self.assertTrue(result["mail_settings"]["sandbox_mode"]["enable"]) with override_settings(DEBUG=True): backend = SendgridBackend(api_key="stub") result = backend._build_sg_mail(msg) self.assertIn("mail_settings", result) self.assertIn("sandbox_mode", result["mail_settings"]) self.assertTrue(result["mail_settings"]["sandbox_mode"]["enable"]) with override_settings(DEBUG=True, SENDGRID_SANDBOX_MODE_IN_DEBUG=False): backend = SendgridBackend(api_key="stub") result = backend._build_sg_mail(msg) self.assertIn("mail_settings", result) self.assertIn("sandbox_mode", result["mail_settings"]) self.assertFalse(result["mail_settings"]["sandbox_mode"]["enable"])
class TestMailGeneration(SimpleTestCase): # Any assertDictEqual failures will show the entire diff instead of just a snippet maxDiff = None @classmethod def setUpClass(self): super(TestMailGeneration, self).setUpClass() with override_settings(EMAIL_BACKEND="sendgrid_backend.SendgridBackend", SENDGRID_API_KEY="DUMMY_API_KEY"): self.backend = SendgridBackend() def test_EmailMessage(self): msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [{ "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith" }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!" }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "reply_to": { "email": "*****@*****.**", "name": "Sam Smith" }, "subject": "Hello, World!", "tracking_settings": {"open_tracking": {"enable": True}}, "content": [{ "type": "text/plain", "value": "Hello, World!" }] } self.assertDictEqual(result, expected) def test_EmailMessage_attributes(self): """Test that send_at and categories attributes are correctly written through to output.""" msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) # Set new attributes as message property msg.send_at = 1518108670 msg.categories = ['mammal', 'dog'] msg.ip_pool_name = 'some-name' result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [{ "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }], "subject": "Hello, World!", "send_at": 1518108670, }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "subject": "Hello, World!", "tracking_settings": {"open_tracking": {"enable": True}}, "content": [{ "type": "text/plain", "value": "Hello, World!" }], "categories": ['mammal', 'dog'], "ip_pool_name": "some-name" } self.assertDictEqual(result, expected) def test_EmailMultiAlternatives(self): msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) msg.attach_alternative("<body<div>Hello World!</div></body>", "text/html") # Test CSV attachment msg.attach("file.csv", "1,2,3,4", "text/csv") result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [{ "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith" }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!" }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "reply_to": { "email": "*****@*****.**", "name": "Sam Smith" }, "subject": "Hello, World!", "tracking_settings": {"open_tracking": {"enable": True}}, "attachments": [{ "content": "MSwyLDMsNA==", "filename": "file.csv", "type": "text/csv" }], "content": [{ "type": "text/plain", "value": " ", }, { "type": "text/html", "value": "<body<div>Hello World!</div></body>", }] } self.assertDictEqual(result, expected) def test_EmailMultiAlternatives__unicode_attachment(self): msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) msg.attach_alternative("<body<div>Hello World!</div></body>", "text/html") # Test CSV attachment msg.attach("file.xls", b"\xd0", "application/vnd.ms-excel") msg.attach("file.csv", b"C\xc3\xb4te d\xe2\x80\x99Ivoire", "text/csv") result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [{ "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith" }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!" }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "reply_to": { "email": "*****@*****.**", "name": "Sam Smith" }, "subject": "Hello, World!", "tracking_settings": {"open_tracking": {"enable": True}}, "attachments": [ { "content": "0A==", "filename": "file.xls", "type": "application/vnd.ms-excel" }, { "content": "Q8O0dGUgZOKAmUl2b2lyZQ==", "filename": "file.csv", "type": "text/csv" } ], "content": [{ "type": "text/plain", "value": " ", }, { "type": "text/html", "value": "<body<div>Hello World!</div></body>", }] } self.assertDictEqual(result, expected) def test_reply_to(self): kwargs = { "subject": "Hello, World!", "body": "Hello, World!", "from_email": "Sam Smith <*****@*****.**>", "to": ["John Doe <*****@*****.**>"], "reply_to": ["Sam Smith <*****@*****.**>"], "headers": {"Reply-To": "Stephanie Smith <*****@*****.**>"} } # Test different values in Reply-To header and reply_to prop msg = EmailMessage(**kwargs) with self.assertRaises(ValueError): self.backend._build_sg_mail(msg) # Test different names (but same email) in Reply-To header and reply_to prop kwargs["headers"] = {"Reply-To": "Bad Name <*****@*****.**>"} msg = EmailMessage(**kwargs) with self.assertRaises(ValueError): self.backend._build_sg_mail(msg) # Test same name/email in both Reply-To header and reply_to prop kwargs["headers"] = {"Reply-To": "Sam Smith <*****@*****.**>"} msg = EmailMessage(**kwargs) result = self.backend._build_sg_mail(msg) self.assertDictEqual(result["reply_to"], {"email": "*****@*****.**", "name": "Sam Smith"}) def test_mime(self): msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) content = '<body><img src="cid:linux_penguin" /></body>' msg.attach_alternative(content, "text/html") with open("test/linux-penguin.png", "rb") as f: img = MIMEImage(f.read()) img.add_header("Content-ID", "<linux_penguin>") msg.attach(img) result = self.backend._build_sg_mail(msg) self.assertEqual(len(result["content"]), 2) self.assertDictEqual(result["content"][0], {"type": "text/plain", "value": " "}) self.assertDictEqual(result["content"][1], {"type": "text/html", "value": content}) self.assertEqual(len(result["attachments"]), 1) self.assertEqual(result["attachments"][0]["content_id"], "linux_penguin") with open("test/linux-penguin.png", "rb") as f: if sys.version_info >= (3.0, 0.0, ): self.assertEqual(bytearray(result["attachments"][0]["content"], "utf-8"), base64.b64encode(f.read())) else: self.assertEqual(result["attachments"][0]["content"], base64.b64encode(f.read())) self.assertEqual(result["attachments"][0]["type"], "image/png") def test_templating(self): msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) msg.template_id = "test_template" result = self.backend._build_sg_mail(msg) self.assertIn("template_id", result) self.assertEquals(result["template_id"], "test_template") def test_asm(self): msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) msg.asm = {"group_id": 1} result = self.backend._build_sg_mail(msg) self.assertIn("asm", result) self.assertIn("group_id", result["asm"]) del msg.asm["group_id"] with self.assertRaises(KeyError): self.backend._build_sg_mail(msg) msg.asm = {"group_id": 1, "groups_to_display": [2, 3, 4], "bad_key": None} result = self.backend._build_sg_mail(msg) self.assertIn("asm", result) self.assertIn("group_id", result["asm"]) self.assertIn("groups_to_display", result["asm"]) def test_EmailMessage_custom_args(self): msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) msg.custom_args = {"arg_1": "Foo", "arg_2": "bar"} result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [{ "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith" }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!", "custom_args": {"arg_1": "Foo", "arg_2": "bar"} }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "reply_to": { "email": "*****@*****.**", "name": "Sam Smith" }, "subject": "Hello, World!", "tracking_settings": {"open_tracking": {"enable": True}}, "content": [{ "type": "text/plain", "value": "Hello, World!" }], } self.assertDictEqual(result, expected) """
class TestMailGeneration(SimpleTestCase): # Any assertDictEqual failures will show the entire diff instead of just a snippet maxDiff = None @classmethod def setUpClass(self): super(TestMailGeneration, self).setUpClass() with override_settings(EMAIL_BACKEND="sendgrid_backend.SendgridBackend", SENDGRID_API_KEY="DUMMY_API_KEY"): self.backend = SendgridBackend() def test_EmailMessage(self): msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [{ "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith" }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!" }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "reply_to": { "email": "*****@*****.**", "name": "Sam Smith" }, "subject": "Hello, World!", "content": [{ "type": "text/plain", "value": "Hello, World!" }] } self.assertDictEqual(result, expected) def test_EmailMultiAlternatives(self): msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) msg.attach_alternative("<body<div>Hello World!</div></body>", "text/html") result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [{ "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith" }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!" }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "reply_to": { "email": "*****@*****.**", "name": "Sam Smith" }, "subject": "Hello, World!", "content": [{ "type": "text/plain", "value": " ", }, { "type": "text/html", "value": "<body<div>Hello World!</div></body>", }] } self.assertDictEqual(result, expected) def test_reply_to(self): kwargs = { "subject": "Hello, World!", "body": "Hello, World!", "from_email": "Sam Smith <*****@*****.**>", "to": ["John Doe <*****@*****.**>"], "reply_to": ["Sam Smith <*****@*****.**>"], "headers": {"Reply-To": "Stephanie Smith <*****@*****.**>"} } # Test different values in Reply-To header and reply_to prop msg = EmailMessage(**kwargs) with self.assertRaises(ValueError): self.backend._build_sg_mail(msg) # Test different names (but same email) in Reply-To header and reply_to prop kwargs["headers"] = {"Reply-To": "Bad Name <*****@*****.**>"} msg = EmailMessage(**kwargs) with self.assertRaises(ValueError): self.backend._build_sg_mail(msg) # Test same name/email in both Reply-To header and reply_to prop kwargs["headers"] = {"Reply-To": "Sam Smith <*****@*****.**>"} msg = EmailMessage(**kwargs) result = self.backend._build_sg_mail(msg) self.assertDictEqual(result["reply_to"], {"email": "*****@*****.**", "name": "Sam Smith"}) def test_mime(self): msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) content = '<body><img src="cid:linux_penguin" /></body>' msg.attach_alternative(content, "text/html") with open("test/linux-penguin.png", "rb") as f: img = MIMEImage(f.read()) img.add_header("Content-ID", "linux_penguin") msg.attach(img) result = self.backend._build_sg_mail(msg) self.assertEqual(len(result["content"]), 2) self.assertDictEqual(result["content"][0], {"type": "text/plain", "value": " "}) self.assertDictEqual(result["content"][1], {"type": "text/html", "value": content}) self.assertEqual(len(result["attachments"]), 1) with open("test/linux-penguin.png", "rb") as f: if sys.version_info >= (3.0, 0.0, ): self.assertEqual(bytearray(result["attachments"][0]["content"], "utf-8"), base64.b64encode(f.read())) else: self.assertEqual(result["attachments"][0]["content"], base64.b64encode(f.read())) self.assertEqual(result["attachments"][0]["type"], "image/png") """
class TestMailGeneration(SimpleTestCase): # Any assertDictEqual failures will show the entire diff instead of just a snippet maxDiff = None @classmethod def setUpClass(self): super(TestMailGeneration, self).setUpClass() with override_settings( EMAIL_BACKEND="sendgrid_backend.SendgridBackend", SENDGRID_API_KEY="DUMMY_API_KEY", ): self.backend = SendgridBackend() def test_EmailMessage(self): """ Tests that an EmailMessage object is properly serialized into the format expected by Sendgrid's API """ msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) result = self.backend._build_sg_mail(msg) expected = { "personalizations": [ { "to": [ {"email": "*****@*****.**", "name": "John Doe"}, { "email": "*****@*****.**", }, ], "cc": [ { "email": "*****@*****.**", "name": "Stephanie Smith", } ], "bcc": [ {"email": "*****@*****.**", "name": "Sarah Smith"} ], "subject": "Hello, World!", } ], "from": {"email": "*****@*****.**", "name": "Sam Smith"}, "mail_settings": {"sandbox_mode": {"enable": False}}, "reply_to": {"email": "*****@*****.**", "name": "Sam Smith"}, "subject": "Hello, World!", "tracking_settings": { "click_tracking": {"enable": True, "enable_text": True}, "open_tracking": {"enable": True}, }, "content": [{"type": "text/plain", "value": "Hello, World!"}], } self.assertDictEqual(result, expected) def test_EmailMessage_attributes(self): """ Test that send_at and categories attributes are correctly written through to output. """ msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) # Set new attributes as message property msg.send_at = 1518108670 if SENDGRID_5: msg.categories = ["mammal", "dog"] else: msg.categories = ["dog", "mammal"] msg.ip_pool_name = "some-name" result = self.backend._build_sg_mail(msg) expected = { "personalizations": [ { "to": [ {"email": "*****@*****.**", "name": "John Doe"}, { "email": "*****@*****.**", }, ], "subject": "Hello, World!", "send_at": 1518108670, } ], "from": {"email": "*****@*****.**", "name": "Sam Smith"}, "mail_settings": {"sandbox_mode": {"enable": False}}, "subject": "Hello, World!", "tracking_settings": { "click_tracking": {"enable": True, "enable_text": True}, "open_tracking": {"enable": True}, }, "content": [{"type": "text/plain", "value": "Hello, World!"}], "categories": ["mammal", "dog"], "ip_pool_name": "some-name", } self.assertDictEqual(result, expected) def test_EmailMultiAlternatives(self): """ Tests that django's EmailMultiAlternatives class works as expected. """ msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) msg.attach_alternative("<body<div>Hello World!</div></body>", "text/html") # Test CSV attachment msg.attach("file.csv", "1,2,3,4", "text/csv") result = self.backend._build_sg_mail(msg) expected = { "personalizations": [ { "to": [ {"email": "*****@*****.**", "name": "John Doe"}, { "email": "*****@*****.**", }, ], "cc": [ { "email": "*****@*****.**", "name": "Stephanie Smith", } ], "bcc": [ {"email": "*****@*****.**", "name": "Sarah Smith"} ], "subject": "Hello, World!", } ], "from": {"email": "*****@*****.**", "name": "Sam Smith"}, "mail_settings": {"sandbox_mode": {"enable": False}}, "reply_to": {"email": "*****@*****.**", "name": "Sam Smith"}, "subject": "Hello, World!", "tracking_settings": { "click_tracking": {"enable": True, "enable_text": True}, "open_tracking": {"enable": True}, }, "attachments": [ {"content": "MSwyLDMsNA==", "filename": "file.csv", "type": "text/csv"} ], "content": [ { "type": "text/plain", "value": " ", }, { "type": "text/html", "value": "<body<div>Hello World!</div></body>", }, ], } self.assertDictEqual(result, expected) def test_EmailMultiAlternatives__unicode_attachment(self): """ Tests that django's EmailMultiAlternatives class works as expected with a unicode-formatted attachment. """ msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) msg.attach_alternative("<body<div>Hello World!</div></body>", "text/html") # Test CSV attachment attachments = [ ("file.xls", b"\xd0", "application/vnd.ms-excel"), ("file.csv", b"C\xc3\xb4te d\xe2\x80\x99Ivoire", "text/csv"), ] if SENDGRID_5: for a in attachments: msg.attach(*a) else: for a in reversed(attachments): msg.attach(*a) result = self.backend._build_sg_mail(msg) expected = { "personalizations": [ { "to": [ {"email": "*****@*****.**", "name": "John Doe"}, { "email": "*****@*****.**", }, ], "cc": [ { "email": "*****@*****.**", "name": "Stephanie Smith", } ], "bcc": [ {"email": "*****@*****.**", "name": "Sarah Smith"} ], "subject": "Hello, World!", } ], "from": {"email": "*****@*****.**", "name": "Sam Smith"}, "mail_settings": {"sandbox_mode": {"enable": False}}, "reply_to": {"email": "*****@*****.**", "name": "Sam Smith"}, "subject": "Hello, World!", "tracking_settings": { "click_tracking": {"enable": True, "enable_text": True}, "open_tracking": {"enable": True}, }, "attachments": [ { "content": "0A==", "filename": "file.xls", "type": "application/vnd.ms-excel", }, { "content": "Q8O0dGUgZOKAmUl2b2lyZQ==", "filename": "file.csv", "type": "text/csv", }, ], "content": [ { "type": "text/plain", "value": " ", }, { "type": "text/html", "value": "<body<div>Hello World!</div></body>", }, ], } self.assertDictEqual(result, expected) def test_reply_to(self): """ Tests reply-to functionality """ kwargs = { "subject": "Hello, World!", "body": "Hello, World!", "from_email": "Sam Smith <*****@*****.**>", "to": ["John Doe <*****@*****.**>"], "reply_to": ["Sam Smith <*****@*****.**>"], "headers": {"Reply-To": "Stephanie Smith <*****@*****.**>"}, } # Test different values in Reply-To header and reply_to prop msg = EmailMessage(**kwargs) with self.assertRaises(ValueError): self.backend._build_sg_mail(msg) # Test different names (but same email) in Reply-To header and reply_to prop kwargs["headers"] = {"Reply-To": "Bad Name <*****@*****.**>"} msg = EmailMessage(**kwargs) with self.assertRaises(ValueError): self.backend._build_sg_mail(msg) # Test same name/email in both Reply-To header and reply_to prop kwargs["headers"] = {"Reply-To": "Sam Smith <*****@*****.**>"} msg = EmailMessage(**kwargs) result = self.backend._build_sg_mail(msg) self.assertDictEqual( result["reply_to"], {"email": "*****@*****.**", "name": "Sam Smith"} ) def test_mime(self): """ Tests MIMEImage support for the EmailMultiAlternatives class """ msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) content = '<body><img src="cid:linux_penguin" /></body>' msg.attach_alternative(content, "text/html") with open("test/linux-penguin.png", "rb") as f: img = MIMEImage(f.read()) img.add_header("Content-ID", "<linux_penguin>") msg.attach(img) result = self.backend._build_sg_mail(msg) self.assertEqual(len(result["content"]), 2) self.assertDictEqual(result["content"][0], {"type": "text/plain", "value": " "}) self.assertDictEqual( result["content"][1], {"type": "text/html", "value": content} ) self.assertEqual(len(result["attachments"]), 1) self.assertEqual(result["attachments"][0]["content_id"], "linux_penguin") with open("test/linux-penguin.png", "rb") as f: self.assertEqual( bytearray(result["attachments"][0]["content"], "utf-8"), base64.b64encode(f.read()), ) self.assertEqual(result["attachments"][0]["type"], "image/png") def test_templating_sendgrid_v5(self): """ Tests that basic templating functionality works. This is a simple check and the results are valid for both Sendgrid versions 5 and 6. """ msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) msg.template_id = "test_template" result = self.backend._build_sg_mail(msg) self.assertIn("template_id", result) self.assertEquals(result["template_id"], "test_template") def test_templating_sendgrid(self): """ Tests more complex templating scenarios for versions 5 and 6 of sendgrid todo: break this up into separate tests """ if SENDGRID_5: msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) msg.template_id = "test_template" result = self.backend._build_sg_mail(msg) self.assertIn("template_id", result) self.assertEquals(result["template_id"], "test_template") # Testing that for sendgrid v5 the code behave in the same way self.assertEquals( result["content"], [{"type": "text/plain", "value": "Hello, World!"}] ) self.assertEquals(result["subject"], "Hello, World!") self.assertEquals(result["personalizations"][0]["subject"], "Hello, World!") else: msg = EmailMessage( from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) msg.template_id = "test_template" msg.dynamic_template_data = { "subject": "Hello, World!", "content": "Hello, World!", "link": "http://hello.com", } result = self.backend._build_sg_mail(msg) self.assertIn("template_id", result) self.assertEquals(result["template_id"], "test_template") self.assertEquals( result["personalizations"][0]["dynamic_template_data"], msg.dynamic_template_data, ) # Subject and content should not be between request param self.assertNotIn("subject", result) self.assertNotIn("content", result) def test_asm(self): """ Tests that unsubscribe group functionality works """ msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) msg.asm = {"group_id": 1} result = self.backend._build_sg_mail(msg) self.assertIn("asm", result) self.assertIn("group_id", result["asm"]) del msg.asm["group_id"] with self.assertRaises(KeyError): self.backend._build_sg_mail(msg) msg.asm = {"group_id": 1, "groups_to_display": [2, 3, 4], "bad_key": None} result = self.backend._build_sg_mail(msg) self.assertIn("asm", result) self.assertIn("group_id", result["asm"]) self.assertIn("groups_to_display", result["asm"]) def test_EmailMessage_custom_args(self): """ Tests that the custom_args property is serialized correctly """ msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) msg.custom_args = {"arg_1": "Foo", "arg_2": "bar"} result = self.backend._build_sg_mail(msg) expected = { "personalizations": [ { "to": [ {"email": "*****@*****.**", "name": "John Doe"}, { "email": "*****@*****.**", }, ], "cc": [ { "email": "*****@*****.**", "name": "Stephanie Smith", } ], "bcc": [ {"email": "*****@*****.**", "name": "Sarah Smith"} ], "subject": "Hello, World!", "custom_args": {"arg_1": "Foo", "arg_2": "bar"}, } ], "from": {"email": "*****@*****.**", "name": "Sam Smith"}, "mail_settings": {"sandbox_mode": {"enable": False}}, "reply_to": {"email": "*****@*****.**", "name": "Sam Smith"}, "subject": "Hello, World!", "tracking_settings": { "click_tracking": {"enable": True, "enable_text": True}, "open_tracking": {"enable": True}, }, "content": [{"type": "text/plain", "value": "Hello, World!"}], } self.assertDictEqual(result, expected) """
def setUpClass(self): super(TestMailGeneration, self).setUpClass() with override_settings(EMAIL_BACKEND="sendgrid_backend.SendgridBackend", SENDGRID_API_KEY="DUMMY_API_KEY"): self.backend = SendgridBackend()
class TestMailGeneration(SimpleTestCase): # Any assertDictEqual failures will show the entire diff instead of just a snippet maxDiff = None @classmethod def setUpClass(self): super(TestMailGeneration, self).setUpClass() with override_settings(EMAIL_BACKEND="sendgrid_backend.SendgridBackend", SENDGRID_API_KEY="DUMMY_API_KEY"): self.backend = SendgridBackend() def test_EmailMessage(self): msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [{ "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith" }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!" }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "reply_to": { "email": "*****@*****.**", "name": "Sam Smith" }, "subject": "Hello, World!", "tracking_settings": {"open_tracking": {"enable": True}}, "content": [{ "type": "text/plain", "value": "Hello, World!" }] } self.assertDictEqual(result, expected) def test_EmailMessage_attributes(self): """Test that send_at and categories attributes are correctly written through to output.""" msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) # Set new attributes as message property msg.send_at = 1518108670 msg.categories = ['mammal', 'dog'] msg.ip_pool_name = 'some-name' result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [{ "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }], "subject": "Hello, World!", "send_at": 1518108670, }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "subject": "Hello, World!", "tracking_settings": {"open_tracking": {"enable": True}}, "content": [{ "type": "text/plain", "value": "Hello, World!" }], "categories": ['mammal', 'dog'], "ip_pool_name": "some-name" } self.assertDictEqual(result, expected) def test_EmailMultiAlternatives(self): msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) msg.attach_alternative("<body<div>Hello World!</div></body>", "text/html") # Test CSV attachment msg.attach("file.csv", "1,2,3,4", "text/csv") result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [{ "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith" }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!" }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "reply_to": { "email": "*****@*****.**", "name": "Sam Smith" }, "subject": "Hello, World!", "tracking_settings": {"open_tracking": {"enable": True}}, "attachments": [{ "content": "MSwyLDMsNA==", "filename": "file.csv", "type": "text/csv" }], "content": [{ "type": "text/plain", "value": " ", }, { "type": "text/html", "value": "<body<div>Hello World!</div></body>", }] } self.assertDictEqual(result, expected) def test_EmailMultiAlternatives__unicode_attachment(self): msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) msg.attach_alternative("<body<div>Hello World!</div></body>", "text/html") # Test CSV attachment msg.attach("file.xls", b"\xd0", "application/vnd.ms-excel") msg.attach("file.csv", b"C\xc3\xb4te d\xe2\x80\x99Ivoire", "text/csv") result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [{ "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith" }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!" }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "reply_to": { "email": "*****@*****.**", "name": "Sam Smith" }, "subject": "Hello, World!", "tracking_settings": {"open_tracking": {"enable": True}}, "attachments": [ { "content": "0A==", "filename": "file.xls", "type": "application/vnd.ms-excel" }, { "content": "Q8O0dGUgZOKAmUl2b2lyZQ==", "filename": "file.csv", "type": "text/csv" } ], "content": [{ "type": "text/plain", "value": " ", }, { "type": "text/html", "value": "<body<div>Hello World!</div></body>", }] } self.assertDictEqual(result, expected) def test_reply_to(self): kwargs = { "subject": "Hello, World!", "body": "Hello, World!", "from_email": "Sam Smith <*****@*****.**>", "to": ["John Doe <*****@*****.**>"], "reply_to": ["Sam Smith <*****@*****.**>"], "headers": {"Reply-To": "Stephanie Smith <*****@*****.**>"} } # Test different values in Reply-To header and reply_to prop msg = EmailMessage(**kwargs) with self.assertRaises(ValueError): self.backend._build_sg_mail(msg) # Test different names (but same email) in Reply-To header and reply_to prop kwargs["headers"] = {"Reply-To": "Bad Name <*****@*****.**>"} msg = EmailMessage(**kwargs) with self.assertRaises(ValueError): self.backend._build_sg_mail(msg) # Test same name/email in both Reply-To header and reply_to prop kwargs["headers"] = {"Reply-To": "Sam Smith <*****@*****.**>"} msg = EmailMessage(**kwargs) result = self.backend._build_sg_mail(msg) self.assertDictEqual(result["reply_to"], {"email": "*****@*****.**", "name": "Sam Smith"}) def test_mime(self): msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) content = '<body><img src="cid:linux_penguin" /></body>' msg.attach_alternative(content, "text/html") with open("test/linux-penguin.png", "rb") as f: img = MIMEImage(f.read()) img.add_header("Content-ID", "<linux_penguin>") msg.attach(img) result = self.backend._build_sg_mail(msg) self.assertEqual(len(result["content"]), 2) self.assertDictEqual(result["content"][0], {"type": "text/plain", "value": " "}) self.assertDictEqual(result["content"][1], {"type": "text/html", "value": content}) self.assertEqual(len(result["attachments"]), 1) self.assertEqual(result["attachments"][0]["content_id"], "linux_penguin") with open("test/linux-penguin.png", "rb") as f: if sys.version_info >= (3.0, 0.0, ): self.assertEqual(bytearray(result["attachments"][0]["content"], "utf-8"), base64.b64encode(f.read())) else: self.assertEqual(result["attachments"][0]["content"], base64.b64encode(f.read())) self.assertEqual(result["attachments"][0]["type"], "image/png") def test_templating(self): msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) msg.template_id = "test_template" result = self.backend._build_sg_mail(msg) self.assertIn("template_id", result) self.assertEquals(result["template_id"], "test_template") def test_asm(self): msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) msg.asm = {"group_id": 1} result = self.backend._build_sg_mail(msg) self.assertIn("asm", result) self.assertIn("group_id", result["asm"]) del msg.asm["group_id"] with self.assertRaises(KeyError): self.backend._build_sg_mail(msg) msg.asm = {"group_id": 1, "groups_to_display": [2, 3, 4], "bad_key": None} result = self.backend._build_sg_mail(msg) self.assertIn("asm", result) self.assertIn("group_id", result["asm"]) self.assertIn("groups_to_display", result["asm"]) """
def test_init_no_setting(self): backend = SendgridBackend(api_key="DUMMY_API_KEY") with self.assertRaises(ImproperlyConfigured): backend = SendgridBackend()
def test_sandbox_mode(self): """ Tests combinations of DEBUG and SENDGRID_SANDBOX_MODE_IN_DEBUG to ensure that the behavior is as expected. """ msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>"], ) # Sandbox mode should be False with override_settings(DEBUG=False, SENDGRID_SANDBOX_MODE_IN_DEBUG=True): backend = SendgridBackend(api_key="stub") result = backend._build_sg_mail(msg) self.assertIn("mail_settings", result) self.assertIn("sandbox_mode", result["mail_settings"]) self.assertFalse(result["mail_settings"]["sandbox_mode"]["enable"]) # Sandbox mode should be True with override_settings(DEBUG=True, SENDGRID_SANDBOX_MODE_IN_DEBUG=True): backend = SendgridBackend(api_key="stub") result = backend._build_sg_mail(msg) self.assertIn("mail_settings", result) self.assertIn("sandbox_mode", result["mail_settings"]) self.assertTrue(result["mail_settings"]["sandbox_mode"]["enable"]) # Sandbox mode should be True (by default when DEBUG==True) with override_settings(DEBUG=True): backend = SendgridBackend(api_key="stub") result = backend._build_sg_mail(msg) self.assertIn("mail_settings", result) self.assertIn("sandbox_mode", result["mail_settings"]) self.assertTrue(result["mail_settings"]["sandbox_mode"]["enable"]) # Sandbox mode should be False with override_settings(DEBUG=True, SENDGRID_SANDBOX_MODE_IN_DEBUG=False): backend = SendgridBackend(api_key="stub") result = backend._build_sg_mail(msg) self.assertIn("mail_settings", result) self.assertIn("sandbox_mode", result["mail_settings"]) self.assertFalse(result["mail_settings"]["sandbox_mode"]["enable"])
class TestMailGeneration(SimpleTestCase): # Any assertDictEqual failures will show the entire diff instead of just a snippet maxDiff = None @classmethod def setUpClass(self): super(TestMailGeneration, self).setUpClass() with override_settings( EMAIL_BACKEND="sendgrid_backend.SendgridBackend", SENDGRID_API_KEY="DUMMY_API_KEY", ): self.backend = SendgridBackend() def test_EmailMessage(self): """ Tests that an EmailMessage object is properly serialized into the format expected by Sendgrid's API """ msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [ { "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }, ], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith", }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!", }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "reply_to": { "email": "*****@*****.**", "name": "Sam Smith" }, "subject": "Hello, World!", "tracking_settings": { "click_tracking": { "enable": True, "enable_text": True }, "open_tracking": { "enable": True }, }, "content": [{ "type": "text/plain", "value": "Hello, World!" }], } self.assertDictEqual(result, expected) def test_EmailMessage_attributes(self): """ Test that send_at and categories attributes are correctly written through to output. """ msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) # Set new attributes as message property msg.send_at = 1518108670 if SENDGRID_5: msg.categories = ["mammal", "dog"] else: msg.categories = ["dog", "mammal"] msg.ip_pool_name = "some-name" result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [ { "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }, ], "subject": "Hello, World!", "send_at": 1518108670, }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "subject": "Hello, World!", "tracking_settings": { "click_tracking": { "enable": True, "enable_text": True }, "open_tracking": { "enable": True }, }, "content": [{ "type": "text/plain", "value": "Hello, World!" }], "categories": ["mammal", "dog"], "ip_pool_name": "some-name", } self.assertDictEqual(result, expected) def test_EmailMultiAlternatives(self): """ Tests that django's EmailMultiAlternatives class works as expected. """ msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) msg.attach_alternative("<body<div>Hello World!</div></body>", "text/html") # Test CSV attachment msg.attach("file.csv", "1,2,3,4", "text/csv") result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [ { "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }, ], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith", }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!", }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "reply_to": { "email": "*****@*****.**", "name": "Sam Smith" }, "subject": "Hello, World!", "tracking_settings": { "click_tracking": { "enable": True, "enable_text": True }, "open_tracking": { "enable": True }, }, "attachments": [{ "content": "MSwyLDMsNA==", "filename": "file.csv", "type": "text/csv" }], "content": [ { "type": "text/plain", "value": " ", }, { "type": "text/html", "value": "<body<div>Hello World!</div></body>", }, ], } self.assertDictEqual(result, expected) def test_EmailMultiAlternatives__unicode_attachment(self): """ Tests that django's EmailMultiAlternatives class works as expected with a unicode-formatted attachment. """ msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) msg.attach_alternative("<body<div>Hello World!</div></body>", "text/html") # Test CSV attachment attachments = [ ("file.xls", b"\xd0", "application/vnd.ms-excel"), ("file.csv", b"C\xc3\xb4te d\xe2\x80\x99Ivoire", "text/csv"), ] if SENDGRID_5: for a in attachments: msg.attach(*a) else: for a in reversed(attachments): msg.attach(*a) result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [ { "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }, ], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith", }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!", }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "reply_to": { "email": "*****@*****.**", "name": "Sam Smith" }, "subject": "Hello, World!", "tracking_settings": { "click_tracking": { "enable": True, "enable_text": True }, "open_tracking": { "enable": True }, }, "attachments": [ { "content": "0A==", "filename": "file.xls", "type": "application/vnd.ms-excel", }, { "content": "Q8O0dGUgZOKAmUl2b2lyZQ==", "filename": "file.csv", "type": "text/csv", }, ], "content": [ { "type": "text/plain", "value": " ", }, { "type": "text/html", "value": "<body<div>Hello World!</div></body>", }, ], } self.assertDictEqual(result, expected) def test_reply_to(self): """ Tests reply-to functionality """ kwargs = { "subject": "Hello, World!", "body": "Hello, World!", "from_email": "Sam Smith <*****@*****.**>", "to": ["John Doe <*****@*****.**>"], "reply_to": ["Sam Smith <*****@*****.**>"], "headers": { "Reply-To": "Stephanie Smith <*****@*****.**>" }, } # Test different values in Reply-To header and reply_to prop msg = EmailMessage(**kwargs) with self.assertRaises(ValueError): self.backend._build_sg_mail(msg) # Test different names (but same email) in Reply-To header and reply_to prop kwargs["headers"] = {"Reply-To": "Bad Name <*****@*****.**>"} msg = EmailMessage(**kwargs) with self.assertRaises(ValueError): self.backend._build_sg_mail(msg) # Test same name/email in both Reply-To header and reply_to prop kwargs["headers"] = {"Reply-To": "Sam Smith <*****@*****.**>"} msg = EmailMessage(**kwargs) result = self.backend._build_sg_mail(msg) self.assertDictEqual(result["reply_to"], { "email": "*****@*****.**", "name": "Sam Smith" }) def test_mime(self): """ Tests MIMEImage support for the EmailMultiAlternatives class """ msg = EmailMultiAlternatives( subject="Hello, World!", body=" ", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) content = '<body><img src="cid:linux_penguin" /></body>' msg.attach_alternative(content, "text/html") with open("test/linux-penguin.png", "rb") as f: img = MIMEImage(f.read()) img.add_header("Content-ID", "<linux_penguin>") msg.attach(img) with open("test/linux-penguin.png", "rb") as f: img = MIMEImage(f.read()) img.add_header("Content-ID", "<linux_penguin_with_method>") img.set_param("method", "REQUEST") msg.attach(img) result = self.backend._build_sg_mail(msg) self.assertEqual(len(result["content"]), 2) self.assertDictEqual(result["content"][0], { "type": "text/plain", "value": " " }) self.assertDictEqual(result["content"][1], { "type": "text/html", "value": content }) self.assertEqual(len(result["attachments"]), 2) # First test image with no method param found_first_img = False found_second_img = False for attch in result["attachments"]: content_id = attch["content_id"] if content_id == "linux_penguin": found_first_img = True with open("test/linux-penguin.png", "rb") as f: self.assertEqual( bytearray(attch["content"], "utf-8"), base64.b64encode(f.read()), ) self.assertEqual(attch["type"], "image/png") elif content_id == "linux_penguin_with_method": found_second_img = True self.assertEqual(attch["type"], "image/png; method=REQUEST;") else: raise Exception(f"Unexpected content_id {content_id}") self.assertTrue(found_first_img and found_second_img) # Next test image with method param img1 = result["attachments"][1] def test_templating_sendgrid_v5(self): """ Tests that basic templating functionality works. This is a simple check and the results are valid for both Sendgrid versions 5 and 6. """ msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) msg.template_id = "test_template" result = self.backend._build_sg_mail(msg) self.assertIn("template_id", result) self.assertEqual(result["template_id"], "test_template") def test_templating_sendgrid(self): """ Tests more complex templating scenarios for versions 5 and 6 of sendgrid todo: break this up into separate tests """ if SENDGRID_5: msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) msg.template_id = "test_template" result = self.backend._build_sg_mail(msg) self.assertIn("template_id", result) self.assertEqual(result["template_id"], "test_template") # Testing that for sendgrid v5 the code behave in the same way self.assertEqual(result["content"], [{ "type": "text/plain", "value": "Hello, World!" }]) self.assertEqual(result["subject"], "Hello, World!") self.assertEqual(result["personalizations"][0]["subject"], "Hello, World!") else: msg = EmailMessage( from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) msg.template_id = "test_template" msg.dynamic_template_data = { "subject": "Hello, World!", "content": "Hello, World!", "link": "http://hello.com", } result = self.backend._build_sg_mail(msg) self.assertIn("template_id", result) self.assertEqual(result["template_id"], "test_template") self.assertEqual( result["personalizations"][0]["dynamic_template_data"], msg.dynamic_template_data, ) # Subject and content should not be between request param self.assertNotIn("subject", result) self.assertNotIn("content", result) def test_asm(self): """ Tests that unsubscribe group functionality works """ msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], ) msg.asm = {"group_id": 1} result = self.backend._build_sg_mail(msg) self.assertIn("asm", result) self.assertIn("group_id", result["asm"]) del msg.asm["group_id"] with self.assertRaises(KeyError): self.backend._build_sg_mail(msg) msg.asm = { "group_id": 1, "groups_to_display": [2, 3, 4], "bad_key": None } result = self.backend._build_sg_mail(msg) self.assertIn("asm", result) self.assertIn("group_id", result["asm"]) self.assertIn("groups_to_display", result["asm"]) def test_EmailMessage_custom_args(self): """ Tests that the custom_args property is serialized correctly """ msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) msg.custom_args = {"arg_1": "Foo", "arg_2": "bar"} result = self.backend._build_sg_mail(msg) expected = { "personalizations": [{ "to": [ { "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }, ], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith", }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!", "custom_args": { "arg_1": "Foo", "arg_2": "bar" }, }], "from": { "email": "*****@*****.**", "name": "Sam Smith" }, "mail_settings": { "sandbox_mode": { "enable": False } }, "reply_to": { "email": "*****@*****.**", "name": "Sam Smith" }, "subject": "Hello, World!", "tracking_settings": { "click_tracking": { "enable": True, "enable_text": True }, "open_tracking": { "enable": True }, }, "content": [{ "type": "text/plain", "value": "Hello, World!" }], } self.assertDictEqual(result, expected) def test_personalizations_resolution(self): """ Tests that adding a Personalization() object directly to an EmailMessage object works as expected. Written to test functionality introduced in the PR: https://github.com/sklarsa/django-sendgrid-v5/pull/90 """ msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) # Tests that personalizations take priority test_str = "*****@*****.**" test_key_str = "my key" test_val_str = "my val" personalization = Personalization() if SENDGRID_5: personalization.add_to(Email(test_str)) personalization.add_cc(Email(test_str)) personalization.add_bcc(Email(test_str)) else: personalization.add_to(To(test_str)) personalization.add_cc(Cc(test_str)) personalization.add_bcc(Bcc(test_str)) personalization.add_custom_arg(CustomArg(test_key_str, test_val_str)) personalization.add_header(Header(test_key_str, test_val_str)) personalization.add_substitution( Substitution(test_key_str, test_val_str)) msg.personalizations = [personalization] result = self.backend._build_sg_mail(msg) personalization = result["personalizations"][0] for field in ("to", "cc", "bcc"): data = personalization[field] self.assertEqual(len(data), 1) self.assertEqual(data[0]["email"], test_str) for field in ("custom_args", "headers", "substitutions"): data = personalization[field] self.assertEqual(len(data), 1) self.assertIn(test_key_str, data) self.assertEqual(test_val_str, data[test_key_str]) def test_dict_to_personalization(self): """ Tests that dict_to_personalization works """ data = { "to": [ { "email": "*****@*****.**", "name": "John Doe" }, { "email": "*****@*****.**", }, ], "cc": [{ "email": "*****@*****.**", "name": "Stephanie Smith", }], "bcc": [{ "email": "*****@*****.**", "name": "Sarah Smith" }], "subject": "Hello, World!", "custom_args": { "arg_1": "Foo", "arg_2": "bar" }, "headers": { "header_1": "Foo", "header_2": "Bar" }, "substitutions": { "sub_a": "foo", "sub_b": "bar" }, "send_at": 1518108670, "dynamic_template_data": { "subject": "Hello, World!", "content": "Hello, World!", "link": "http://hello.com", }, } p = dict_to_personalization(data) fields_to_test = ( ("tos", "to"), ("ccs", "cc"), ("bccs", "bcc"), ("subject", "subject"), ("custom_args", "custom_args"), ("headers", "headers"), ("substitutions", "substitutions"), ("send_at", "send_at"), ("dynamic_template_data", "dynamic_template_data"), ) for arg, key in fields_to_test: val = getattr(p, arg) if type(val) == list: self.assertListEqual(val, data[key]) elif type(val) == dict: self.assertDictEqual(val, data[key]) else: self.assertEqual(val, data[key]) def test_build_personalization_errors(self): msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) test_str = "*****@*****.**" test_key_str = "my key" test_val_str = "my val" personalization = Personalization() if SENDGRID_5: personalization.add_cc(Email(test_str)) personalization.add_bcc(Email(test_str)) else: personalization.add_cc(Cc(test_str)) personalization.add_bcc(Bcc(test_str)) personalization.add_custom_arg(CustomArg(test_key_str, test_val_str)) personalization.add_header(Header(test_key_str, test_val_str)) personalization.add_substitution( Substitution(test_key_str, test_val_str)) msg.personalizations = [personalization] self.assertRaisesRegex( ValueError, "Each msg personalization must have recipients", self.backend._build_sg_mail, msg, ) delattr(msg, "personalizations") msg.dynamic_template_data = {"obi_wan": "hello there"} self.assertRaisesRegex( ValueError, r"Either msg\.to or msg\.personalizations \(with recipients\) must be set", self.backend._build_sg_mail, msg, ) def test_tracking_config(self): msg = EmailMessage( subject="Hello, World!", body="Hello, World!", from_email="Sam Smith <*****@*****.**>", to=["John Doe <*****@*****.**>", "*****@*****.**"], cc=["Stephanie Smith <*****@*****.**>"], bcc=["Sarah Smith <*****@*****.**>"], reply_to=["Sam Smith <*****@*****.**>"], ) ganalytics = Ganalytics( enable=True, utm_source="my-source", utm_campaign="my-campaign", utm_medium="my-medium", ) if SENDGRID_5: tracking_settings = TrackingSettings() tracking_settings.ganalytics = ganalytics tracking_settings.click_tracking = ClickTracking(enable=False) msg.tracking_settings = tracking_settings else: msg.tracking_settings = TrackingSettings( ganalytics=ganalytics, click_tracking=ClickTracking(enable=False)) mail = self.backend._build_sg_mail(msg) tracking_settings = mail.get("tracking_settings") assert tracking_settings assert not tracking_settings["click_tracking"]["enable"] assert "ganalytics" in tracking_settings assert tracking_settings["ganalytics"]["utm_source"] == "my-source"