Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
 def setUpClass(self):
     super(TestMailGeneration, self).setUpClass()
     with override_settings(
         EMAIL_BACKEND="sendgrid_backend.SendgridBackend",
         SENDGRID_API_KEY="DUMMY_API_KEY",
     ):
         self.backend = SendgridBackend()
Ejemplo n.º 3
0
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,
    })
Ejemplo n.º 4
0
 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"])
Ejemplo n.º 7
0
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")

    """
    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"])
Ejemplo n.º 10
0
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)

    """
Ejemplo n.º 11
0
 def setUpClass(self):
     super(TestMailGeneration, self).setUpClass()
     with override_settings(EMAIL_BACKEND="sendgrid_backend.SendgridBackend",
                            SENDGRID_API_KEY="DUMMY_API_KEY"):
         self.backend = SendgridBackend()
Ejemplo n.º 12
0
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"])

    """
Ejemplo n.º 13
0
    def test_init_no_setting(self):
        backend = SendgridBackend(api_key="DUMMY_API_KEY")

        with self.assertRaises(ImproperlyConfigured):
            backend = SendgridBackend()
Ejemplo n.º 14
0
    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"])
Ejemplo n.º 15
0
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"