Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for dynamic template data to Email class #908

Merged
merged 3 commits into from
Jun 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions sendgrid/helpers/mail/dynamic_template_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ class DynamicTemplateData(object):

def __init__(self, dynamic_template_data=None, p=0):
"""Data for a transactional template.
Should be JSON-serializeable structure.
Should be JSON-serializable structure.

:param dynamic_template_data: Data for a transactional template.
:type dynamic_template_data: A JSON-serializeable structure
:type dynamic_template_data: A JSON-serializable structure
:param name: p is the Personalization object or Personalization object
index
:type name: Personalization, integer, optional
Expand All @@ -25,7 +25,7 @@ def __init__(self, dynamic_template_data=None, p=0):
def dynamic_template_data(self):
"""Data for a transactional template.

:rtype: A JSON-serializeable structure
:rtype: A JSON-serializable structure
"""
return self._dynamic_template_data

Expand All @@ -34,7 +34,7 @@ def dynamic_template_data(self, value):
"""Data for a transactional template.

:param value: Data for a transactional template.
:type value: A JSON-serializeable structure
:type value: A JSON-serializable structure
"""
self._dynamic_template_data = value

Expand All @@ -59,7 +59,7 @@ def personalization(self, value):
def __str__(self):
"""Get a JSON representation of this object.

:rtype: A JSON-serializeable structure
:rtype: A JSON-serializable structure
"""
return str(self.get())

Expand All @@ -68,6 +68,6 @@ def get(self):
Get a JSON-ready representation of this DynamicTemplateData object.

:returns: Data for a transactional template.
:rtype: A JSON-serializeable structure.
:rtype: A JSON-serializable structure.
"""
return self.dynamic_template_data
49 changes: 33 additions & 16 deletions sendgrid/helpers/mail/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
html_entity_decode = __html_parser__.unescape

try:
basestring = basestring
basestring = basestring
except NameError:
# Define basestring when Python >= 3.0
basestring = str
Expand All @@ -32,7 +32,8 @@ def __init__(self,
name=None,
substitutions=None,
subject=None,
p=0):
p=0,
dynamic_template_data=None):
"""Create an Email with the given address and name.

Either fill the separate name and email fields, or pass all information
Expand All @@ -41,17 +42,19 @@ def __init__(self,
:type email: string, optional
:param name: Name for this sender or recipient.
:type name: string, optional
:param substitutions: String substitutions to be applied to the email.
:type substitutions: list(Substitution), optional
:param subject: Subject for this sender or recipient.
:type subject: string, optional
:param p: p is the Personalization object or Personalization object
index
:type p: Personalization, integer, optional
:param dynamic_template_data: Data for a dynamic transactional template.
:type dynamic_template_data: DynamicTemplateData, optional
"""
self._name = None
self._email = None
self._substitutions = None
self._subject = None
self._personalization = None
self._personalization = p

if email and not name:
# allows passing emails as "Example Name <[email protected]>"
Expand All @@ -64,14 +67,11 @@ def __init__(self,
if name is not None:
self.name = name

if substitutions is not None:
self.substitutions = substitutions

if subject is not None:
self.subject = subject

if p is not None:
self.personalization = p
# Note that these only apply to To Emails (see Personalization.add_to)
# and should be moved but have not been for compatibility.
self._substitutions = substitutions
self._dynamic_template_data = dynamic_template_data
self._subject = subject

@property
def name(self):
Expand Down Expand Up @@ -129,7 +129,7 @@ def email(self, value):
@property
def substitutions(self):
"""A list of Substitution objects. These substitutions will apply to
the text and html content of the body of your email, in addition
the text and html content of the body of your email, in addition
to the subject and reply-to parameters. The total collective size
of your substitutions may not exceed 10,000 bytes per
personalization object.
Expand All @@ -141,20 +141,37 @@ def substitutions(self):
@substitutions.setter
def substitutions(self, value):
"""A list of Substitution objects. These substitutions will apply to
the text and html content of the body of your email, in addition to
the text and html content of the body of your email, in addition to
the subject and reply-to parameters. The total collective size of
your substitutions may not exceed 10,000 bytes per personalization
object.

:param value: A list of Substitution objects. These substitutions will
apply to the text and html content of the body of your email, in
apply to the text and html content of the body of your email, in
addition to the subject and reply-to parameters. The total collective
size of your substitutions may not exceed 10,000 bytes per
personalization object.
:type value: list(Substitution)
"""
self._substitutions = value

@property
def dynamic_template_data(self):
"""Data for a dynamic transactional template.

:rtype: DynamicTemplateData
"""
return self._dynamic_template_data

@dynamic_template_data.setter
def dynamic_template_data(self, value):
"""Data for a dynamic transactional template.

:param value: DynamicTemplateData
:type value: DynamicTemplateData
"""
self._dynamic_template_data = value

@property
def subject(self):
"""Subject for this sender or recipient.
Expand Down
10 changes: 5 additions & 5 deletions sendgrid/helpers/mail/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,17 +185,17 @@ def _set_emails(

@property
def personalizations(self):
"""A list of one or more Personaliztion objects
"""A list of one or more Personalization objects

:rtype: list(Personalization)
"""
return self._personalizations

def add_personalization(self, personalization, index=0):
"""Add a Personaliztion object
"""Add a Personalization object

:param personalizations: Add a Personalization object
:type personalizations: Personalization
:param personalization: Add a Personalization object
:type personalization: Personalization
:param index: The index where to add the Personalization
:type index: int
"""
Expand Down Expand Up @@ -627,7 +627,7 @@ def dynamic_template_data(self, value):
"""Data for a transactional template

:param value: Data for a transactional template
:type value: DynamicTemplateData, a JSON-serializeable structure
:type value: DynamicTemplateData, a JSON-serializable structure
"""
if not isinstance(value, DynamicTemplateData):
value = DynamicTemplateData(value)
Expand Down
20 changes: 14 additions & 6 deletions sendgrid/helpers/mail/personalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,16 @@ def add_to(self, email):
self.add_substitution(substitution)
else:
self.add_substitution(email.substitutions)

if email.dynamic_template_data:
thinkingserious marked this conversation as resolved.
Show resolved Hide resolved
self.dynamic_template_data = email.dynamic_template_data

if email.subject:
if isinstance(email.subject, str):
self.subject = email.subject
else:
self.subject = email.subject.get()

self._tos.append(email.get())

@property
Expand Down Expand Up @@ -149,10 +154,10 @@ def add_substitution(self, substitution):

:type substitution: Substitution
"""
if isinstance(substitution, dict):
self._substitutions.append(substitution)
else:
self._substitutions.append(substitution.get())
if not isinstance(substitution, dict):
substitution = substitution.get()

self._substitutions.append(substitution)

@property
def custom_args(self):
Expand Down Expand Up @@ -190,14 +195,17 @@ def send_at(self, value):
@property
def dynamic_template_data(self):
"""Data for dynamic transactional template.
Should be JSON-serializeable structure.
Should be JSON-serializable structure.

:rtype: JSON-serializeable structure
:rtype: JSON-serializable structure
"""
return self._dynamic_template_data

@dynamic_template_data.setter
def dynamic_template_data(self, value):
if not isinstance(value, dict):
value = value.get()

self._dynamic_template_data = value

def get(self):
Expand Down
97 changes: 80 additions & 17 deletions test/test_mail_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@
EmailMessage = message.Message

from sendgrid.helpers.mail import (
Asm, ApiKeyIncludedException, Attachment, BccSettings,
BypassListManagement, Category, ClickTracking, Content, CustomArg,
DynamicTemplateData, Email, FooterSettings, From, Ganalytics, Header,
Mail, MailSettings, OpenTracking, Personalization, SandBoxMode, Section,
SendGridException, SpamCheck, Subject, SubscriptionTracking, Substitution,
TrackingSettings, To, ValidateApiKey
Asm, Attachment,
ClickTracking, Content,
DynamicTemplateData, Email, From,
Mail, Personalization,
Subject, Substitution, To, TrackingSettings
)


Expand Down Expand Up @@ -210,18 +209,18 @@ def test_multiple_emails_to_multiple_recipients(self):

to_emails = [
To(email='[email protected]',
name='Example Name 0',
substitutions=[
Substitution('-name-', 'Example Name Substitution 0'),
Substitution('-github-', 'https://example.com/test0'),
],
subject=Subject('Override Global Subject')),
name='Example Name 0',
substitutions=[
Substitution('-name-', 'Example Name Substitution 0'),
Substitution('-github-', 'https://example.com/test0'),
],
subject=Subject('Override Global Subject')),
To(email='[email protected]',
name='Example Name 1',
substitutions=[
Substitution('-name-', 'Example Name Substitution 1'),
Substitution('-github-', 'https://example.com/test1'),
])
name='Example Name 1',
substitutions=[
Substitution('-name-', 'Example Name Substitution 1'),
Substitution('-github-', 'https://example.com/test1'),
])
]
global_substitutions = Substitution('-time-', '2019-01-01 00:00:00')
message = Mail(
Expand Down Expand Up @@ -285,6 +284,70 @@ def test_multiple_emails_to_multiple_recipients(self):
}''')
)

def test_dynamic_template_data(self):
self.maxDiff = None

to_emails = [
To(email='[email protected]',
name='Example To 0 Name',
dynamic_template_data=DynamicTemplateData({'name': 'Example 0 Name'})),
To(email='[email protected]',
name='Example To 1 Name',
dynamic_template_data={'name': 'Example 1 Name'})
]
message = Mail(
from_email=From('[email protected]', 'Example From Name'),
to_emails=to_emails,
subject=Subject('Hi!'),
plain_text_content='Hello!',
html_content='<strong>Hello!</strong>',
is_multiple=True)

self.assertEqual(
message.get(),
json.loads(r'''{
"content": [
{
"type": "text/plain",
"value": "Hello!"
},
{
"type": "text/html",
"value": "<strong>Hello!</strong>"
}
],
"from": {
"email": "[email protected]",
"name": "Example From Name"
},
"personalizations": [
{
"dynamic_template_data": {
"name": "Example 1 Name"
},
"to": [
{
"email": "[email protected]",
"name": "Example To 1 Name"
}
]
},
{
"dynamic_template_data": {
"name": "Example 0 Name"
},
"to": [
{
"email": "[email protected]",
"name": "Example To 0 Name"
}
]
}
],
"subject": "Hi!"
}''')
)

def test_kitchen_sink(self):
from sendgrid.helpers.mail import (
Mail, From, To, Cc, Bcc, Subject, Substitution, Header,
Expand Down
Loading