Skip to content

Commit

Permalink
feat: allow personalization of the From name and email for each recip…
Browse files Browse the repository at this point in the history
…ient (#1020)

* feat: allow personalization of the From name and email for each recipient
  • Loading branch information
Bilal Boussayoud authored Oct 25, 2021
1 parent 2e12f1c commit a97e83a
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 14 deletions.
12 changes: 8 additions & 4 deletions examples/helpers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ For more information on parameters and usage, see [here](../mail/mail.py)

### Creating Personalizations

To create personalizations, you need a dictionary to store all your email components. See example [here](https://github.com/sendgrid/sendgrid-python/blob/0b683169b08d3a7c204107cd333be33053297e74/examples/helpers/mail_example.py#L47)
After creating a dictionary, you can go ahead and create a `Personalization` object.
The personalization helper can be used to create personalizations and customize various aspects of an email. See example [here](mail_example.py) in `build_multiple_emails_personalized()`, and refer [here](https://docs.sendgrid.com/for-developers/sending-email/personalizations) for more documentation.
```
mock_personalization = Personalization()
for to_addr in personalization['to_list']:
mock_personalization.add_to(to_addr)
for to_addr in personalization['to_list']:
mock_personalization.add_to(to_addr)
mock_personalization.set_from(from_addr)
mock_personalization.add_cc(cc_addr)
# etc...
```

### Creating Attachments
Expand Down
65 changes: 56 additions & 9 deletions examples/helpers/mail_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def build_hello_email():
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail, From, To, Subject, PlainTextContent, HtmlContent, SendGridException

message = Mail(from_email=From('from@example.com.com', 'Example From Name'),
message = Mail(from_email=From('from@example.com', 'Example From Name'),
to_emails=To('to@example.com', 'Example To Name'),
subject=Subject('Sending with SendGrid is Fun'),
plain_text_content=PlainTextContent('and easy to do anywhere, even with Python'),
Expand All @@ -26,25 +26,30 @@ def build_hello_email():
except SendGridException as e:
print(e.message)

for cc_addr in personalization['cc_list']:
mock_personalization = Personalization()
personalization_dict = get_mock_personalization_dict()

for cc_addr in personalization_dict['cc_list']:
mock_personalization.add_to(cc_addr)

for bcc_addr in personalization['bcc_list']:
for bcc_addr in personalization_dict['bcc_list']:
mock_personalization.add_bcc(bcc_addr)

for header in personalization['headers']:
for header in personalization_dict['headers']:
mock_personalization.add_header(header)

for substitution in personalization['substitutions']:
for substitution in personalization_dict['substitutions']:
mock_personalization.add_substitution(substitution)

for arg in personalization['custom_args']:
for arg in personalization_dict['custom_args']:
mock_personalization.add_custom_arg(arg)

mock_personalization.subject = personalization['subject']
mock_personalization.send_at = personalization['send_at']
return mock_personalization
mock_personalization.subject = personalization_dict['subject']
mock_personalization.send_at = personalization_dict['send_at']

message.add_personalization(mock_personalization)

return message

def get_mock_personalization_dict():
"""Get a dict of personalization mock."""
Expand Down Expand Up @@ -78,6 +83,36 @@ def get_mock_personalization_dict():
mock_pers['send_at'] = 1443636843
return mock_pers

def build_multiple_emails_personalized():
import json
from sendgrid.helpers.mail import Mail, From, To, Cc, Bcc, Subject, PlainTextContent, \
HtmlContent, SendGridException, Personalization

# Note that the domain for all From email addresses must match
message = Mail(from_email=From('from@example.com', 'Example From Name'),
subject=Subject('Sending with SendGrid is Fun'),
plain_text_content=PlainTextContent('and easy to do anywhere, even with Python'),
html_content=HtmlContent('<strong>and easy to do anywhere, even with Python</strong>'))

mock_personalization = Personalization()
mock_personalization.add_to(To('test@example.com', 'Example User 1'))
mock_personalization.add_cc(Cc('test1@example.com', 'Example User 2'))
message.add_personalization(mock_personalization)

mock_personalization_2 = Personalization()
mock_personalization_2.add_to(To('test2@example.com', 'Example User 3'))
mock_personalization_2.set_from(From('from@example.com', 'Example From Name 2'))
mock_personalization_2.add_bcc(Bcc('test3@example.com', 'Example User 4'))
message.add_personalization(mock_personalization_2)

try:
print(json.dumps(message.get(), sort_keys=True, indent=4))
return message.get()

except SendGridException as e:
print(e.message)

return message

def build_attachment1():
"""Build attachment mock. Make sure your content is base64 encoded before passing into attachment.content.
Expand Down Expand Up @@ -308,6 +343,15 @@ def build_kitchen_sink():

return message

def send_multiple_emails_personalized():
# Assumes you set your environment variable:
# https://github.com/sendgrid/sendgrid-python/blob/HEAD/TROUBLESHOOTING.md#environment-variables-and-your-sendgrid-api-key
message = build_multiple_emails_personalized()
sendgrid_client = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
response = sendgrid_client.send(message=message)
print(response.status_code)
print(response.body)
print(response.headers)

def send_hello_email():
# Assumes you set your environment variable:
Expand All @@ -334,5 +378,8 @@ def send_kitchen_sink():
## this will actually send an email
# send_hello_email()

## this will send multiple emails
# send_multiple_emails_personalized()

## this will only send an email if you set SandBox Mode to False
# send_kitchen_sink()
21 changes: 20 additions & 1 deletion sendgrid/helpers/mail/personalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Personalization(object):
def __init__(self):
"""Create an empty Personalization and initialize member variables."""
self._tos = []
self._from_email = None
self._ccs = []
self._bccs = []
self._subject = None
Expand All @@ -26,7 +27,10 @@ def add_email(self, email):
if email_type.__name__ == 'Bcc':
self.add_bcc(email)
return
raise ValueError('Please use a To, Cc or Bcc object.')
if email_type.__name__ == 'From':
self.from_email = email
return
raise ValueError('Please use a To, From, Cc or Bcc object.')

def _get_unique_recipients(self, recipients):
unique_recipients = []
Expand Down Expand Up @@ -77,6 +81,17 @@ def add_to(self, email):

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

@property
def from_email(self):
return self._from_email

@from_email.setter
def from_email(self, value):
self._from_email = value

def set_from(self, email):
self._from_email = email.get()

@property
def ccs(self):
"""A list of recipients who will receive copies of this email.
Expand Down Expand Up @@ -236,6 +251,10 @@ def get(self):
if value:
personalization[key[:-1]] = value

from_value = getattr(self, 'from_email')
if from_value:
personalization['from'] = from_value

for key in ['subject', 'send_at', 'dynamic_template_data']:
value = getattr(self, key)
if value:
Expand Down
9 changes: 9 additions & 0 deletions test/test_mail_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,15 @@ def test_personalization_add_email_filters_out_duplicate_to_emails_ignoring_case

self.assertEqual([to_email.get()], p.tos)

def test_personalization_set_from_email(self):
self.maxDiff = None

p = Personalization()
from_email = From('test+from@example.com', 'Example From')
p.set_from(from_email)

self.assertEqual(from_email.get(), p.from_email)

def test_personalization_filters_out_duplicate_cc_emails(self):
self.maxDiff = None

Expand Down
1 change: 1 addition & 0 deletions use_cases/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ This directory provides examples for specific use cases of this library. Please
* [Send a Single Email to a Single Recipient](send_a_single_email_to_a_single_recipient.md)
* [Send a Single Email to Multiple Recipients](send_a_single_email_to_multiple_recipients.md)
* [Send Multiple Emails to Multiple Recipients](send_multiple_emails_to_multiple_recipients.md)
* [Send Multiple Emails with Personalizations](send_multiple_emails_personalizations.md)
* [Kitchen Sink - an example with all settings used](kitchen_sink.md)
* [Transactional Templates](transactional_templates.md)
* [Attachments](attachment.md)
Expand Down
32 changes: 32 additions & 0 deletions use_cases/send_multiple_emails_personalizations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
```python
import os
import json
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail, Personalization, From, To, Cc, Bcc

# Note that the domain for all From email addresses must match
message = Mail(
from_email=('from@example.com', 'Example From Name'),
subject='Sending with Twilio SendGrid is Fun',
html_content='<strong>and easy to do anywhere, even with Python</strong>')

personalization1 = Personalization()
personalization1.add_email(To('test0@example.com', 'Example Name 0'))
personalization1.add_email(Cc('test1@example.com', 'Example Name 1'))
message.add_personalization(personalization1)

personalization2 = Personalization()
personalization2.add_email(To('test2@example.com', 'Example Name 2'))
personalization2.add_email(Bcc('test3@example.com', 'Example Name 3'))
personalization2.add_email(From('from2@example.com', 'Example From Name 2'))
message.add_personalization(personalization2)

try:
sendgrid_client = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
response = sendgrid_client.send(message)
print(response.status_code)
print(response.body)
print(response.headers)
except Exception as e:
print(e.message)
```

0 comments on commit a97e83a

Please sign in to comment.