From 539dd36e9d30afa98abe8a4c01e257b26b64613e Mon Sep 17 00:00:00 2001 From: Wojciech Bartosiak Date: Fri, 3 Aug 2018 17:45:46 +0200 Subject: [PATCH 1/8] adding dynamic template data --- sendgrid/helpers/mail/personalization.py | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/sendgrid/helpers/mail/personalization.py b/sendgrid/helpers/mail/personalization.py index 8bb4bed0b..196a1203e 100644 --- a/sendgrid/helpers/mail/personalization.py +++ b/sendgrid/helpers/mail/personalization.py @@ -13,6 +13,7 @@ def __init__(self): self._substitutions = [] self._custom_args = [] self._send_at = None + self._dynamic_template_data = list() @property def tos(self): @@ -158,6 +159,25 @@ def send_at(self): def send_at(self, value): self._send_at = value + @property + def dynamic_template_data(self): + """The DynamicTemplateData that will be carried along with this Personalization. + + :rtype: dict + """ + return self._dynamic_template_data + + @dynamic_template_data.setter + def dynamic_template_data(self, value): + self._dynamic_template_data = value + + def add_dynamic_template_data(self, dynamic_template_data): + """Append item to DynamicTemplateData + + :type dynamic_template_data: dict + """ + self._dynamic_template_data.append(dynamic_template_data) + def get(self): """ Get a JSON-ready representation of this Personalization. @@ -198,4 +218,10 @@ def get(self): if self.send_at is not None: personalization["send_at"] = self.send_at + + if self.dynamic_template_data: + dynamic_template_data = dict() + for item in self.dynamic_template_data: + dynamic_template_data.update(item) + personalization['dynamic_template_data'] = dynamic_template_data return personalization From 18936d153c9adbf4fe570e6bc8d23684785ba915 Mon Sep 17 00:00:00 2001 From: Wojciech Bartosiak Date: Fri, 3 Aug 2018 17:45:52 +0200 Subject: [PATCH 2/8] added tests --- test/test_mail.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/test/test_mail.py b/test/test_mail.py index 7721b5205..76e280b6c 100644 --- a/test/test_mail.py +++ b/test/test_mail.py @@ -562,3 +562,42 @@ def test_disable_tracking(self): def test_directly_setting_substitutions(self): personalization = Personalization() personalization.substitutions = [{'a': 0}] + + def test_simple_dynamic_template_data(self): + """Minimum required to send an email""" + mail = Mail() + + mail.from_email = Email("test@example.com") + + mail.subject = "Hello World from the SendGrid Python Library" + + personalization = Personalization() + personalization.add_to(Email("test@example.com")) + personalization.add_dynamic_template_data({'foo': 'bar'}) + mail.add_personalization(personalization) + + mail.add_content(Content("text/plain", "some text here")) + mail.add_content( + Content( + "text/html", + "some text here")) + + self.assertEqual( + json.dumps( + mail.get(), + sort_keys=True), + '{"content": [{"type": "text/plain", "value": "some text here"}, ' + '{"type": "text/html", ' + '"value": "some text here"}], ' + '"from": {"email": "test@example.com"}, ' + '"personalizations": [{' + '"dynamic_template_data": {"foo": "bar"}, ' + '"to": [{"email": "test@example.com"}]' + '}], ' + '"subject": "Hello World from the SendGrid Python Library"' + '}' + ) + + self.assertTrue(isinstance(str(mail), str)) + + From 7edd5db7d45327aedd7f0bcb48d39b4c622dc4f4 Mon Sep 17 00:00:00 2001 From: Wojciech Bartosiak Date: Fri, 3 Aug 2018 18:09:08 +0200 Subject: [PATCH 3/8] adding dynamic tag --- sendgrid/helpers/mail/__init__.py | 1 + sendgrid/helpers/mail/dynamic_template_tag.py | 43 +++++++++++++++++++ sendgrid/helpers/mail/personalization.py | 4 +- test/test_mail.py | 6 +-- 4 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 sendgrid/helpers/mail/dynamic_template_tag.py diff --git a/sendgrid/helpers/mail/__init__.py b/sendgrid/helpers/mail/__init__.py index 1dd769e99..2b6fdc650 100644 --- a/sendgrid/helpers/mail/__init__.py +++ b/sendgrid/helpers/mail/__init__.py @@ -22,3 +22,4 @@ from .substitution import Substitution from .tracking_settings import TrackingSettings from .validators import ValidateAPIKey +from .dynamic_template_tag import DynamicTemplateTag diff --git a/sendgrid/helpers/mail/dynamic_template_tag.py b/sendgrid/helpers/mail/dynamic_template_tag.py new file mode 100644 index 000000000..f17ed7289 --- /dev/null +++ b/sendgrid/helpers/mail/dynamic_template_tag.py @@ -0,0 +1,43 @@ +class DynamicTemplateTag(object): + """A dynamic template tag can be used to be applied to the text and HTML contents of + the body of your email, as well as in the Subject and Reply-To parameters. + """ + + def __init__(self, key=None, value=None): + """Create a DynamicTemplateTag with the given key and value. + + :param key: Text to be replaced with "value" param + :type key: string, optional + :param value: Value to substitute into email, can be any JSON serializable object + :type value: any + """ + self._key = key + self._value = value + + @property + def key(self): + return self._key + + @key.setter + def key(self, value): + self._key = value + + @property + def value(self): + return self._value + + @value.setter + def value(self, value): + self._value = value + + def get(self): + """ + Get a JSON-ready representation of this Substitution. + + :returns: This DynamicTemplateTag, ready for use in a request body. + :rtype: dict + """ + dynamic_template_tag = {} + if self.key is not None and self.value is not None: + dynamic_template_tag[self.key] = self.value + return dynamic_template_tag diff --git a/sendgrid/helpers/mail/personalization.py b/sendgrid/helpers/mail/personalization.py index 196a1203e..645e6ae52 100644 --- a/sendgrid/helpers/mail/personalization.py +++ b/sendgrid/helpers/mail/personalization.py @@ -174,9 +174,9 @@ def dynamic_template_data(self, value): def add_dynamic_template_data(self, dynamic_template_data): """Append item to DynamicTemplateData - :type dynamic_template_data: dict + :type dynamic_template_data: DynamicTemplateTag """ - self._dynamic_template_data.append(dynamic_template_data) + self._dynamic_template_data.append(dynamic_template_data.get()) def get(self): """ diff --git a/test/test_mail.py b/test/test_mail.py index 76e280b6c..89ed0ba83 100644 --- a/test/test_mail.py +++ b/test/test_mail.py @@ -26,8 +26,8 @@ SubscriptionTracking, Substitution, TrackingSettings, - ValidateAPIKey -) + ValidateAPIKey, + DynamicTemplateTag) try: import unittest2 as unittest @@ -573,7 +573,7 @@ def test_simple_dynamic_template_data(self): personalization = Personalization() personalization.add_to(Email("test@example.com")) - personalization.add_dynamic_template_data({'foo': 'bar'}) + personalization.add_dynamic_template_data(DynamicTemplateTag('foo', 'bar')) mail.add_personalization(personalization) mail.add_content(Content("text/plain", "some text here")) From d83b3f70c8044c2af490f02e5f40eafdad6c9b53 Mon Sep 17 00:00:00 2001 From: Wojciech Bartosiak Date: Fri, 3 Aug 2018 18:09:22 +0200 Subject: [PATCH 4/8] added documentation --- use_cases/dynamic_templates.md | 132 +++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 use_cases/dynamic_templates.md diff --git a/use_cases/dynamic_templates.md b/use_cases/dynamic_templates.md new file mode 100644 index 000000000..cecc71457 --- /dev/null +++ b/use_cases/dynamic_templates.md @@ -0,0 +1,132 @@ +# Dynamic Transactional Templates + +For this example, we assume you have created a [dynamic transactional template](https://sendgrid.com/docs/User_Guide/Transactional_Templates/Create_and_edit_dynamic_transactional_templates.html). Following is the template content we used for testing. + +Template ID (replace with your own): + +```text +13b8f94f-bcae-4ec6-b752-70d6cb59f932 +``` + +Email Subject: + +```text +{{subject}} +``` + +Template Body: + +```html + + + + + +Hello {{name}}, +

+I'm glad you are trying out the dynamic template feature! +

+

+ + + + + {{#each this}} + + + + + {{/each}} +
+
Values provided
+
{{@key}}
{{this}}
+

+

+I hope you are having a great day :) +

+ + +``` + +## With Mail Helper Class + +```python +import sendgrid +import os +from sendgrid.helpers.mail import Email, Content, DynamicTemplateTag, Mail +try: + # Python 3 + import urllib.request as urllib +except ImportError: + # Python 2 + import urllib2 as urllib + +sg = sendgrid.SendGridAPIClient(apikey=os.environ.get('SENDGRID_API_KEY')) +from_email = Email("test@example.com") +subject = "I'm replacing the subject tag" +to_email = Email("test@example.com") +content = Content("text/html", "I'm replacing the body tag") +mail = Mail(from_email, subject, to_email, content) +mail.personalizations[0].add_dynamic_template_data(DynamicTemplateTag("name", "Example User")) +mail.personalizations[0].add_dynamic_template_data(DynamicTemplateTag("foo", "bar")) +mail.personalizations[0].add_dynamic_template_data(DynamicTemplateTag("extra", "SG rocks!")) +mail.template_id = "13b8f94f-bcae-4ec6-b752-70d6cb59f932" +try: + response = sg.client.mail.send.post(request_body=mail.get()) +except urllib.HTTPError as e: + print (e.read()) + exit() +print(response.status_code) +print(response.body) +print(response.headers) +``` + +## Without Mail Helper Class + +```python +import sendgrid +import os +try: + # Python 3 + import urllib.request as urllib +except ImportError: + # Python 2 + import urllib2 as urllib + +sg = sendgrid.SendGridAPIClient(apikey=os.environ.get('SENDGRID_API_KEY')) +data = { + "personalizations": [ + { + "to": [ + { + "email": "test@example.com" + } + ], + "substitutions": { + "-name-": "Example User", + "-city-": "Denver" + }, + "subject": "I'm replacing the subject tag" + }, + ], + "from": { + "email": "test@example.com" + }, + "content": [ + { + "type": "text/html", + "value": "I'm replacing the body tag" + } + ], + "template_id": "13b8f94f-bcae-4ec6-b752-70d6cb59f932" +} +try: + response = sg.client.mail.send.post(request_body=data) +except urllib.HTTPError as e: + print (e.read()) + exit() +print(response.status_code) +print(response.body) +print(response.headers) +``` + From 90ea913cb924a21e71f32a52c45a509d461de39e Mon Sep 17 00:00:00 2001 From: Wojciech Bartosiak Date: Fri, 3 Aug 2018 18:10:50 +0200 Subject: [PATCH 5/8] included docs --- use_cases/README.md | 1 + .../{dynamic_templates.md => dynamic_transactional_templates.md} | 0 2 files changed, 1 insertion(+) rename use_cases/{dynamic_templates.md => dynamic_transactional_templates.md} (100%) diff --git a/use_cases/README.md b/use_cases/README.md index 188464d09..1f6c64fc0 100644 --- a/use_cases/README.md +++ b/use_cases/README.md @@ -15,6 +15,7 @@ This directory provides examples for specific use cases of this library. Please * [Asynchronous Mail Send](asynchronous_mail_send.md) * [Attachment](attachment.md) * [Transactional Templates](transational_templates.md) +* [Dynamic Transactional Templates](dynamic_transactional_templates.md) ### Library Features * [Error Handling](error_handling.md) \ No newline at end of file diff --git a/use_cases/dynamic_templates.md b/use_cases/dynamic_transactional_templates.md similarity index 100% rename from use_cases/dynamic_templates.md rename to use_cases/dynamic_transactional_templates.md From 80c7c54bff62936b203c096dace9e4de939bdfd7 Mon Sep 17 00:00:00 2001 From: Wojciech Bartosiak Date: Fri, 3 Aug 2018 18:24:18 +0200 Subject: [PATCH 6/8] improved docs when not using helper class --- use_cases/dynamic_transactional_templates.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/use_cases/dynamic_transactional_templates.md b/use_cases/dynamic_transactional_templates.md index cecc71457..0d8057532 100644 --- a/use_cases/dynamic_transactional_templates.md +++ b/use_cases/dynamic_transactional_templates.md @@ -102,10 +102,7 @@ data = { "email": "test@example.com" } ], - "substitutions": { - "-name-": "Example User", - "-city-": "Denver" - }, + "dynamic_template_data": {"extra": "SG rocks!", "foo": "bar", "name": "Example User"}, "subject": "I'm replacing the subject tag" }, ], From 30a6be7329d777995ac0b34c538acb99d00ad4a9 Mon Sep 17 00:00:00 2001 From: af4ro <1997anshul@gmail.com> Date: Fri, 10 Aug 2018 10:37:40 -0700 Subject: [PATCH 7/8] Changed defaults, code cleanup and added an extensive test --- sendgrid/helpers/mail/dynamic_template_tag.py | 2 +- sendgrid/helpers/mail/personalization.py | 12 ++++++------ test/test_mail.py | 11 +++++++---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/sendgrid/helpers/mail/dynamic_template_tag.py b/sendgrid/helpers/mail/dynamic_template_tag.py index f17ed7289..fad5baf52 100644 --- a/sendgrid/helpers/mail/dynamic_template_tag.py +++ b/sendgrid/helpers/mail/dynamic_template_tag.py @@ -37,7 +37,7 @@ def get(self): :returns: This DynamicTemplateTag, ready for use in a request body. :rtype: dict """ - dynamic_template_tag = {} + dynamic_template_tag = dict() if self.key is not None and self.value is not None: dynamic_template_tag[self.key] = self.value return dynamic_template_tag diff --git a/sendgrid/helpers/mail/personalization.py b/sendgrid/helpers/mail/personalization.py index 645e6ae52..caea36da7 100644 --- a/sendgrid/helpers/mail/personalization.py +++ b/sendgrid/helpers/mail/personalization.py @@ -1,3 +1,5 @@ +from copy import deepcopy + class Personalization(object): """A Personalization defines who should receive an individual message and how that message should be handled. @@ -13,7 +15,7 @@ def __init__(self): self._substitutions = [] self._custom_args = [] self._send_at = None - self._dynamic_template_data = list() + self._dynamic_template_data = dict() @property def tos(self): @@ -176,7 +178,7 @@ def add_dynamic_template_data(self, dynamic_template_data): :type dynamic_template_data: DynamicTemplateTag """ - self._dynamic_template_data.append(dynamic_template_data.get()) + self._dynamic_template_data.update(dynamic_template_data.get()) def get(self): """ @@ -220,8 +222,6 @@ def get(self): personalization["send_at"] = self.send_at if self.dynamic_template_data: - dynamic_template_data = dict() - for item in self.dynamic_template_data: - dynamic_template_data.update(item) - personalization['dynamic_template_data'] = dynamic_template_data + personalization['dynamic_template_data'] = deepcopy(self.dynamic_template_data) + return personalization diff --git a/test/test_mail.py b/test/test_mail.py index 89ed0ba83..1c18306ee 100644 --- a/test/test_mail.py +++ b/test/test_mail.py @@ -73,7 +73,7 @@ def test_sendgridAPIKey(self): ) #Exception should be thrown - except Exception as e: + except Exception: pass #Exception not thrown @@ -563,8 +563,8 @@ def test_directly_setting_substitutions(self): personalization = Personalization() personalization.substitutions = [{'a': 0}] - def test_simple_dynamic_template_data(self): - """Minimum required to send an email""" + def test_dynamic_template_data(self): + """Test for minimum requirements, redundancy and nested items""" mail = Mail() mail.from_email = Email("test@example.com") @@ -574,6 +574,9 @@ def test_simple_dynamic_template_data(self): personalization = Personalization() personalization.add_to(Email("test@example.com")) personalization.add_dynamic_template_data(DynamicTemplateTag('foo', 'bar')) + personalization.add_dynamic_template_data(DynamicTemplateTag('one', 'more')) + personalization.add_dynamic_template_data(DynamicTemplateTag('foo', 'bar1')) + personalization.add_dynamic_template_data(DynamicTemplateTag('items', [{"total": "100"}, {"more": "things"}])) mail.add_personalization(personalization) mail.add_content(Content("text/plain", "some text here")) @@ -591,7 +594,7 @@ def test_simple_dynamic_template_data(self): '"value": "some text here"}], ' '"from": {"email": "test@example.com"}, ' '"personalizations": [{' - '"dynamic_template_data": {"foo": "bar"}, ' + '"dynamic_template_data": {"foo": "bar1", "items": [{"total": "100"}, {"more": "things"}], "one": "more"}, ' '"to": [{"email": "test@example.com"}]' '}], ' '"subject": "Hello World from the SendGrid Python Library"' From 6671e9546ee9cf374adb49bf82eb42ba8ae9d3cd Mon Sep 17 00:00:00 2001 From: af4ro <1997anshul@gmail.com> Date: Fri, 10 Aug 2018 14:53:44 -0700 Subject: [PATCH 8/8] Example and usage updates --- examples/helpers/mail/mail_example.py | 28 ++++++++++++++++++++ use_cases/dynamic_transactional_templates.md | 10 ++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/examples/helpers/mail/mail_example.py b/examples/helpers/mail/mail_example.py index b2de7f0a0..42a50b028 100644 --- a/examples/helpers/mail/mail_example.py +++ b/examples/helpers/mail/mail_example.py @@ -212,6 +212,34 @@ def send_kitchen_sink(): print(response.body) +def dynamic_template_usage(): + """ + Sample usage of dynamic (handlebars) transactional templates. + To make this work, you should have dynamic template created within your + SendGrid account. + In this example the template may look like: +

Hello {{name}}! Here is {{foo}} and also {{extra}}!

+ """ + sg = SendGridAPIClient(apikey=os.environ.get('SENDGRID_API_KEY')) + from_email = Email("test@example.com") + subject = "I'm replacing the subject tag" + to_email = Email("test@example.com") + content = Content("text/html", "I'm replacing the body tag") + mail = Mail(from_email, subject, to_email, content) + + p = Personalization() + p.add_dynamic_template_data(DynamicTemplateTag("name", "Example User")) + p.add_dynamic_template_data(DynamicTemplateTag("foo", "bar")) + p.add_dynamic_template_data(DynamicTemplateTag("extra", "SG rocks!")) + mail.template_id = "13b8f94f-bcae-4ec6-b752-70d6cb59f932" + mail.add_personalization(p) + + response = sg.client.mail.send.post(request_body=mail.get()) + print(response.status_code) + print(response.body) + print(response.headers) + + # this will actually send an email send_hello_email() diff --git a/use_cases/dynamic_transactional_templates.md b/use_cases/dynamic_transactional_templates.md index 0d8057532..e8bf8329d 100644 --- a/use_cases/dynamic_transactional_templates.md +++ b/use_cases/dynamic_transactional_templates.md @@ -67,10 +67,14 @@ subject = "I'm replacing the subject tag" to_email = Email("test@example.com") content = Content("text/html", "I'm replacing the body tag") mail = Mail(from_email, subject, to_email, content) -mail.personalizations[0].add_dynamic_template_data(DynamicTemplateTag("name", "Example User")) -mail.personalizations[0].add_dynamic_template_data(DynamicTemplateTag("foo", "bar")) -mail.personalizations[0].add_dynamic_template_data(DynamicTemplateTag("extra", "SG rocks!")) + +p = Personalization() +p.add_dynamic_template_data(DynamicTemplateTag("name", "Example User")) +p.add_dynamic_template_data(DynamicTemplateTag("foo", "bar")) +p.add_dynamic_template_data(DynamicTemplateTag("extra", "SG rocks!")) mail.template_id = "13b8f94f-bcae-4ec6-b752-70d6cb59f932" +mail.add_personalization(p) + try: response = sg.client.mail.send.post(request_body=mail.get()) except urllib.HTTPError as e: