def test_send_a_single_email_to_multiple_recipients(self): from sendgrid.helpers.mail import (Mail, From, To, Subject, PlainTextContent, HtmlContent) self.maxDiff = None to_emails = [ To('*****@*****.**', 'Example To Name 0'), To('*****@*****.**', 'Example To Name 1') ] message = Mail( from_email=From('*****@*****.**', 'Example From Name'), to_emails=to_emails, 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>')) self.assertEqual( message.get(), json.loads(r'''{ "content": [ { "type": "text/plain", "value": "and easy to do anywhere, even with Python" }, { "type": "text/html", "value": "<strong>and easy to do anywhere, even with Python</strong>" } ], "from": { "email": "*****@*****.**", "name": "Example From Name" }, "personalizations": [ { "to": [ { "email": "*****@*****.**", "name": "Example To Name 0" }, { "email": "*****@*****.**", "name": "Example To Name 1" } ] } ], "subject": "Sending with SendGrid is Fun" }'''))
def test_value_error_is_raised_on_to_emails_set_to_list_of_lists(self): from sendgrid.helpers.mail import (PlainTextContent, HtmlContent) self.maxDiff = None to_emails = [['*****@*****.**', 'Example To Name 0'], ['*****@*****.**', 'Example To Name 1']] with self.assertRaises(ValueError): Mail( from_email=From('*****@*****.**', 'Example From Name'), to_emails=to_emails, 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>' ))
def test_error_is_not_raised_on_to_emails_includes_bcc_cc(self): from sendgrid.helpers.mail import (PlainTextContent, HtmlContent) self.maxDiff = None to_emails = [ To('*****@*****.**', 'Example To Name 0'), Bcc('*****@*****.**', 'Example Bcc Name 1'), Cc('*****@*****.**', 'Example Cc Name 2') ] Mail(from_email=From('*****@*****.**', 'Example From Name'), to_emails=to_emails, 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>'))
def test_unicode_values_in_substitutions_helper(self): from sendgrid.helpers.mail import (Mail, From, To, Subject, PlainTextContent, HtmlContent) self.maxDiff = None message = Mail( from_email=From('*****@*****.**', 'Example From Name'), to_emails=To('*****@*****.**', 'Example To 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>')) message.substitution = Substitution('%city%', u'Αθήνα', p=1) self.assertEqual( message.get(), json.loads(r'''{ "content": [ { "type": "text/plain", "value": "and easy to do anywhere, even with Python" }, { "type": "text/html", "value": "<strong>and easy to do anywhere, even with Python</strong>" } ], "from": { "email": "*****@*****.**", "name": "Example From Name" }, "personalizations": [ { "to": [ { "email": "*****@*****.**", "name": "Example To Name" } ] }, { "substitutions": { "%city%": "Αθήνα" } } ], "subject": "Sending with SendGrid is Fun" }'''))
def create_email( self, to_list: List["str"], subject: str, html_content: str, image: bytes = None, content_type: str = None, send_at: datetime = None, ) -> Mail: """ Create a new sendgrid email object. Params: ------ to_list: List[str] - The recipients list. subject: str - The email subject. html_contentet: str - HTML text to fill the email. image: bytes - A optional image to attachment in email. content_type: str - The content type of the image. send_at: datetime - The datetime when the email must be sended. Return: ------ message: Mail - The sendgrid email object. """ message = Mail() message.from_email = From(self.from_email) message.subject = Subject(subject) _users_list = [] for _to in to_list: _users_list.append(To(_to)) message.to = _users_list if image: ext = str(content_type).split("/")[1] timestamp = datetime.utcnow().strftime("%Y-%m-%d-%H%M%S") message.attachment = Attachment( FileContent(image), FileName(f'event_image-{timestamp}.{ext}'), FileType(str(content_type)), Disposition('attachment')) if send_at: message.send_at = SendAt(self.get_unix_time(send_at), p=0) message.content = Content(MimeType.html, html_content) return message
def warn_ops(num_recipients): mail = Mail() mail.to = To("*****@*****.**") #this declaration looks stupid because of PEP8 rules for line length mail.content = Content( MimeType.text, "The script for sending onboarding \ reminders is sending to {} panelists. That's a big number.".format( num_recipients)) mail.from_email = Email(SENDER_EMAIL, SENDER_NAME) mail.subject = Subject("Many onboarding reminders warning") mail.bcc = Bcc(BCC) response = sg.client.mail.send.post(request_body=mail.get()) logger.write("Ops warning for many reminders.\n", "Number of reminders sent: ", str(num_recipients)) logResponseData(logger, response)
def send_email(self): """Sends alert email and clears the current email draft.""" if not self.write_to_email or not self.messages_to_email: return html_message_body = self.generate_email_body() message = Mail(from_email=From(self.sender_email, 'Cloud Accelerators Alert Manager'), to_emails=[To(self.recipient_email)], subject=Subject( 'Errors in ML Accelerators Tests at {}'.format( datetime.now().strftime("%Y/%m/%d %H:%M:%S"))), plain_text_content=PlainTextContent('empty'), html_content=HtmlContent(html_message_body)) response = self.sendgrid.send(message) self._log( 'Email send attempt response: {}\n{}'.format( response.status_code, response.headers), logging.INFO) self.messages_to_email.clear()
def sending_email(data): email = data['email'] uid = "1" message = Mail() message.to = To(email) message.template_id = "d-5141e682aa76" message.dynamic_template_data = { 'subject': 'sign up verification', 'email': data['email'], 'HOSTING_URL': 'http://ec2-34-226-191-16.compute-1.amazonaws.com', 'first_name': "prathap" } message.subject = Subject('sign up verification email') message.from_email = From('*****@*****.**') sg = SendGridAPIClient("SGYAta2_q") response = sg.send(message) print(sg) print(response)
def send_email(from_address, to_address, subject, body): mail = Mail( from_email=From(from_address, "Districtr"), subject=Subject(subject), to_emails=To(to_address), html_content=HtmlContent(body), ) client = SendGridAPIClient( api_key=current_app.config["SENDGRID_API_KEY"]).client if current_app.config.get("SEND_EMAILS", True) is False: print("Sending mail", mail) return response = client.mail.send.post(request_body=mail.get()) if response.status_code >= 300: raise ApiException("Unable to send email.", status=500)
def test_single_email_to_a_single_recipient_content_reversed(self): """Tests bug found in Issue-451 with Content ordering causing a crash """ from sendgrid.helpers.mail import (Mail, From, To, Subject, PlainTextContent, HtmlContent) self.maxDiff = None message = Mail() message.from_email = From('*****@*****.**', 'Example From Name') message.to = To('*****@*****.**', 'Example To Name') message.subject = Subject('Sending with SendGrid is Fun') message.content = HtmlContent( '<strong>and easy to do anywhere, even with Python</strong>') message.content = PlainTextContent( 'and easy to do anywhere, even with Python') self.assertEqual( message.get(), json.loads(r'''{ "content": [ { "type": "text/plain", "value": "and easy to do anywhere, even with Python" }, { "type": "text/html", "value": "<strong>and easy to do anywhere, even with Python</strong>" } ], "from": { "email": "*****@*****.**", "name": "Example From Name" }, "personalizations": [ { "to": [ { "email": "*****@*****.**", "name": "Example To Name" } ] } ], "subject": "Sending with SendGrid is Fun" }'''))
def build_hello_email(): ## Send a Single Email to a Single Recipient import os import json from sendgrid import SendGridAPIClient from sendgrid.helpers.mail import Mail, From, To, Subject, PlainTextContent, HtmlContent, SendGridException message = Mail(from_email=From('*****@*****.**', 'Example From Name'), to_emails=To('*****@*****.**', 'Example To 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>')) try: print(json.dumps(message.get(), sort_keys=True, indent=4)) return message.get() except SendGridException as e: print(e.message)
def build_hello_email(): ## Send a Single Email to a Single Recipient import os import json from sendgrid import SendGridAPIClient from sendgrid.helpers.mail import Mail, From, To, Subject, PlainTextContent, HtmlContent, SendGridException message = Mail( from_email=From('*****@*****.**', 'Example From Name'), to_emails=To('*****@*****.**', 'Example To 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>')) try: print(json.dumps(message.get(), sort_keys=True, indent=4)) return message.get() except SendGridException as e: print(e.message) for cc_addr in personalization['cc_list']: mock_personalization.add_to(cc_addr) for bcc_addr in personalization['bcc_list']: mock_personalization.add_bcc(bcc_addr) for header in personalization['headers']: mock_personalization.add_header(header) for substitution in personalization['substitutions']: mock_personalization.add_substitution(substitution) for arg in personalization['custom_args']: mock_personalization.add_custom_arg(arg) mock_personalization.subject = personalization['subject'] mock_personalization.send_at = personalization['send_at'] return mock_personalization
def send_email(self): """Sends alert email and clears the current email draft.""" if not self.write_to_email or not self.messages_to_email: return html_message_body = 'New errors in test suite for {}:'.format( self.project_id) html_message_body += '<ul>' for logs_link in self.messages_to_email.keys(): html_message_body += '<li>{}:'.format( 'General errors' if logs_link == _NO_LOGS else \ util.test_name_from_logs_link(logs_link)) html_message_body += '<ul>' for message in self.messages_to_email[logs_link]: html_message_body += '<li>{}</li>'.format(message) # If the error was specific to a certain test, include links to quickly # access the logs from that test. if logs_link != _NO_LOGS: html_message_body += '<li><a href="{}">Stackdriver logs for this ' \ 'run of the test</a></li>'.format(logs_link) html_message_body += '<li>Command to download plaintext logs: ' \ '<code style="background-color:#e3e3e3;">' \ '{}</code></li>'.format( util.download_command_from_logs_link( logs_link)) html_message_body += '</ul>' html_message_body += '</li>' html_message_body += '</ul>' message = Mail(from_email=From(self.sender_email, 'Cloud Accelerators Alert Manager'), to_emails=[To(self.recipient_email)], subject=Subject( 'Errors in ML Accelerators Tests at {}'.format( datetime.now().strftime("%Y/%m/%d %H:%M:%S"))), plain_text_content=PlainTextContent('empty'), html_content=HtmlContent(html_message_body)) response = self.sendgrid.send(message) self._log( 'Email send attempt response: {}\n{}'.format( response.status_code, response.headers), logging.INFO) self.messages_to_email.clear()
def create_email(address, subject, template_name, context): templateLoader = jinja2.FileSystemLoader(searchpath="templates") templateEnv = jinja2.Environment(loader=templateLoader) html_template = templateEnv.get_template(template_name + ".html") html_to_send = html_template.render(context) content = HtmlContent(html_to_send) from_email = From("*****@*****.**", "Unsub Team") to_email = To(address) to_emails = [to_email] if "mmu.ac.uk" in address: to_emails += [Cc("*****@*****.**")] email = Mail(from_email=from_email, subject=Subject(subject), to_emails=to_emails, html_content=content) logger.info((u'sending email "{}" to {}'.format(subject, address))) return email
def send_user_info(self, username, password): html_text = f""" <html> <body> <div style=" max-width: 60%; margin: 0 auto; "> <p>Hello,</p> <p>Your account has been created and ready to use. In order to obtain access to your account please click <a href="https://jomari-designs-app.herokuapp.com/login">here</a> and enter the details below: </p> <ul> <li>username: {username}</li> <li>password: {password}</li> </ul> </div> </body> </html> """ from_email = From("*****@*****.**") to_email = To(self._receiver) subject = Subject('Welcome To Jomari Designs') html_content = HtmlContent(html_text) soup = BeautifulSoup(html_text, features='html.parser') plain_text = soup.get_text() plain_text_content = Content("text/plain", plain_text) message = Mail(from_email, to_email, subject, plain_text_content, html_content) response = self.sendgrid_client.send(message=message) return response
def test_single_email_to_a_single_recipient_with_dynamic_templates(self): from sendgrid.helpers.mail import (Mail, From, To, Subject, PlainTextContent, HtmlContent) self.maxDiff = None message = Mail( from_email=From('*****@*****.**', 'Example From Name'), to_emails=To('*****@*****.**', 'Example To 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>')) message.dynamic_template_data = DynamicTemplateData({ "total": "$ 239.85", "items": [{ "text": "New Line Sneakers", "image": "https://marketing-image-production.s3.amazonaws.com/uploads/8dda1131320a6d978b515cc04ed479df259a458d5d45d58b6b381cae0bf9588113e80ef912f69e8c4cc1ef1a0297e8eefdb7b270064cc046b79a44e21b811802.png", "price": "$ 79.95" }, { "text": "Old Line Sneakers", "image": "https://marketing-image-production.s3.amazonaws.com/uploads/3629f54390ead663d4eb7c53702e492de63299d7c5f7239efdc693b09b9b28c82c924225dcd8dcb65732d5ca7b7b753c5f17e056405bbd4596e4e63a96ae5018.png", "price": "$ 79.95" }, { "text": "Blue Line Sneakers", "image": "https://marketing-image-production.s3.amazonaws.com/uploads/00731ed18eff0ad5da890d876c456c3124a4e44cb48196533e9b95fb2b959b7194c2dc7637b788341d1ff4f88d1dc88e23f7e3704726d313c57f350911dd2bd0.png", "price": "$ 79.95" }], "receipt": True, "name": "Sample Name", "address01": "1234 Fake St.", "address02": "Apt. 123", "city": "Place", "state": "CO", "zip": "80202" }) self.assertEqual( message.get(), json.loads(r'''{ "content": [ { "type": "text/plain", "value": "and easy to do anywhere, even with Python" }, { "type": "text/html", "value": "<strong>and easy to do anywhere, even with Python</strong>" } ], "from": { "email": "*****@*****.**", "name": "Example From Name" }, "personalizations": [ { "dynamic_template_data": { "address01": "1234 Fake St.", "address02": "Apt. 123", "city": "Place", "items": [ { "image": "https://marketing-image-production.s3.amazonaws.com/uploads/8dda1131320a6d978b515cc04ed479df259a458d5d45d58b6b381cae0bf9588113e80ef912f69e8c4cc1ef1a0297e8eefdb7b270064cc046b79a44e21b811802.png", "price": "$ 79.95", "text": "New Line Sneakers" }, { "image": "https://marketing-image-production.s3.amazonaws.com/uploads/3629f54390ead663d4eb7c53702e492de63299d7c5f7239efdc693b09b9b28c82c924225dcd8dcb65732d5ca7b7b753c5f17e056405bbd4596e4e63a96ae5018.png", "price": "$ 79.95", "text": "Old Line Sneakers" }, { "image": "https://marketing-image-production.s3.amazonaws.com/uploads/00731ed18eff0ad5da890d876c456c3124a4e44cb48196533e9b95fb2b959b7194c2dc7637b788341d1ff4f88d1dc88e23f7e3704726d313c57f350911dd2bd0.png", "price": "$ 79.95", "text": "Blue Line Sneakers" } ], "name": "Sample Name", "receipt": true, "state": "CO", "total": "$ 239.85", "zip": "80202" }, "to": [ { "email": "*****@*****.**", "name": "Example To Name" } ] } ], "subject": "Sending with SendGrid is Fun" }'''))
def test_kitchen_sink(self): from sendgrid.helpers.mail import ( Mail, From, To, Cc, Bcc, Subject, Substitution, Header, CustomArg, SendAt, Content, MimeType, Attachment, FileName, FileContent, FileType, Disposition, ContentId, TemplateId, Section, ReplyTo, Category, BatchId, Asm, GroupId, GroupsToDisplay, IpPoolName, MailSettings, BccSettings, BccSettingsEmail, BypassListManagement, FooterSettings, FooterText, FooterHtml, SandBoxMode, SpamCheck, SpamThreshold, SpamUrl, TrackingSettings, ClickTracking, SubscriptionTracking, SubscriptionText, SubscriptionHtml, SubscriptionSubstitutionTag, OpenTracking, OpenTrackingSubstitutionTag, Ganalytics, UtmSource, UtmMedium, UtmTerm, UtmContent, UtmCampaign) self.maxDiff = None message = Mail() # Define Personalizations message.to = To('*****@*****.**', 'Example User1', p=0) message.to = [ To('*****@*****.**', 'Example User2', p=0), To('*****@*****.**', 'Example User3', p=0) ] message.cc = Cc('*****@*****.**', 'Example User4', p=0) message.cc = [ Cc('*****@*****.**', 'Example User5', p=0), Cc('*****@*****.**', 'Example User6', p=0) ] message.bcc = Bcc('*****@*****.**', 'Example User7', p=0) message.bcc = [ Bcc('*****@*****.**', 'Example User8', p=0), Bcc('*****@*****.**', 'Example User9', p=0) ] message.subject = Subject('Sending with SendGrid is Fun 0', p=0) message.header = Header('X-Test1', 'Test1', p=0) message.header = Header('X-Test2', 'Test2', p=0) message.header = [ Header('X-Test3', 'Test3', p=0), Header('X-Test4', 'Test4', p=0) ] message.substitution = Substitution('%name1%', 'Example Name 1', p=0) message.substitution = Substitution('%city1%', 'Example City 1', p=0) message.substitution = [ Substitution('%name2%', 'Example Name 2', p=0), Substitution('%city2%', 'Example City 2', p=0) ] message.custom_arg = CustomArg('marketing1', 'true', p=0) message.custom_arg = CustomArg('transactional1', 'false', p=0) message.custom_arg = [ CustomArg('marketing2', 'false', p=0), CustomArg('transactional2', 'true', p=0) ] message.send_at = SendAt(1461775051, p=0) message.to = To('*****@*****.**', 'Example User10', p=1) message.to = [ To('*****@*****.**', 'Example User11', p=1), To('*****@*****.**', 'Example User12', p=1) ] message.cc = Cc('*****@*****.**', 'Example User13', p=1) message.cc = [ Cc('*****@*****.**', 'Example User14', p=1), Cc('*****@*****.**', 'Example User15', p=1) ] message.bcc = Bcc('*****@*****.**', 'Example User16', p=1) message.bcc = [ Bcc('*****@*****.**', 'Example User17', p=1), Bcc('*****@*****.**', 'Example User18', p=1) ] message.header = Header('X-Test5', 'Test5', p=1) message.header = Header('X-Test6', 'Test6', p=1) message.header = [ Header('X-Test7', 'Test7', p=1), Header('X-Test8', 'Test8', p=1) ] message.substitution = Substitution('%name3%', 'Example Name 3', p=1) message.substitution = Substitution('%city3%', 'Example City 3', p=1) message.substitution = [ Substitution('%name4%', 'Example Name 4', p=1), Substitution('%city4%', 'Example City 4', p=1) ] message.custom_arg = CustomArg('marketing3', 'true', p=1) message.custom_arg = CustomArg('transactional3', 'false', p=1) message.custom_arg = [ CustomArg('marketing4', 'false', p=1), CustomArg('transactional4', 'true', p=1) ] message.send_at = SendAt(1461775052, p=1) message.subject = Subject('Sending with SendGrid is Fun 1', p=1) # The values below this comment are global to entire message message.from_email = From('*****@*****.**', 'Twilio SendGrid') message.reply_to = ReplyTo('*****@*****.**', 'Twilio SendGrid Reply') message.subject = Subject('Sending with SendGrid is Fun 2') message.content = Content(MimeType.text, 'and easy to do anywhere, even with Python') message.content = Content( MimeType.html, '<strong>and easy to do anywhere, even with Python</strong>') message.content = [ Content('text/calendar', 'Party Time!!'), Content('text/custom', 'Party Time 2!!') ] message.attachment = Attachment( FileContent('base64 encoded content 1'), FileName('balance_001.pdf'), FileType('application/pdf'), Disposition('attachment'), ContentId('Content ID 1')) message.attachment = [ Attachment(FileContent('base64 encoded content 2'), FileName('banner.png'), FileType('image/png'), Disposition('inline'), ContentId('Content ID 2')), Attachment(FileContent('base64 encoded content 3'), FileName('banner2.png'), FileType('image/png'), Disposition('inline'), ContentId('Content ID 3')) ] message.template_id = TemplateId( '13b8f94f-bcae-4ec6-b752-70d6cb59f932') message.section = Section('%section1%', 'Substitution for Section 1 Tag') message.section = [ Section('%section2%', 'Substitution for Section 2 Tag'), Section('%section3%', 'Substitution for Section 3 Tag') ] message.header = Header('X-Test9', 'Test9') message.header = Header('X-Test10', 'Test10') message.header = [ Header('X-Test11', 'Test11'), Header('X-Test12', 'Test12') ] message.category = Category('Category 1') message.category = Category('Category 2') message.category = [Category('Category 1'), Category('Category 2')] message.custom_arg = CustomArg('marketing5', 'false') message.custom_arg = CustomArg('transactional5', 'true') message.custom_arg = [ CustomArg('marketing6', 'true'), CustomArg('transactional6', 'false') ] message.send_at = SendAt(1461775053) message.batch_id = BatchId("HkJ5yLYULb7Rj8GKSx7u025ouWVlMgAi") message.asm = Asm(GroupId(1), GroupsToDisplay([1, 2, 3, 4])) message.ip_pool_name = IpPoolName("IP Pool Name") mail_settings = MailSettings() mail_settings.bcc_settings = BccSettings( False, BccSettingsEmail("*****@*****.**")) mail_settings.bypass_list_management = BypassListManagement(False) mail_settings.footer_settings = FooterSettings( True, FooterText("w00t"), FooterHtml("<string>w00t!<strong>")) mail_settings.sandbox_mode = SandBoxMode(True) mail_settings.spam_check = SpamCheck(True, SpamThreshold(5), SpamUrl("https://example.com")) message.mail_settings = mail_settings tracking_settings = TrackingSettings() tracking_settings.click_tracking = ClickTracking(True, False) tracking_settings.open_tracking = OpenTracking( True, OpenTrackingSubstitutionTag("open_tracking")) tracking_settings.subscription_tracking = SubscriptionTracking( True, SubscriptionText("Goodbye"), SubscriptionHtml("<strong>Goodbye!</strong>"), SubscriptionSubstitutionTag("unsubscribe")) tracking_settings.ganalytics = Ganalytics(True, UtmSource("utm_source"), UtmMedium("utm_medium"), UtmTerm("utm_term"), UtmContent("utm_content"), UtmCampaign("utm_campaign")) message.tracking_settings = tracking_settings self.assertEqual( message.get(), json.loads(r'''{ "asm": { "group_id": 1, "groups_to_display": [ 1, 2, 3, 4 ] }, "attachments": [ { "content": "base64 encoded content 3", "content_id": "Content ID 3", "disposition": "inline", "filename": "banner2.png", "type": "image/png" }, { "content": "base64 encoded content 2", "content_id": "Content ID 2", "disposition": "inline", "filename": "banner.png", "type": "image/png" }, { "content": "base64 encoded content 1", "content_id": "Content ID 1", "disposition": "attachment", "filename": "balance_001.pdf", "type": "application/pdf" } ], "batch_id": "HkJ5yLYULb7Rj8GKSx7u025ouWVlMgAi", "categories": [ "Category 2", "Category 1", "Category 2", "Category 1" ], "content": [ { "type": "text/plain", "value": "and easy to do anywhere, even with Python" }, { "type": "text/html", "value": "<strong>and easy to do anywhere, even with Python</strong>" }, { "type": "text/calendar", "value": "Party Time!!" }, { "type": "text/custom", "value": "Party Time 2!!" } ], "custom_args": { "marketing5": "false", "marketing6": "true", "transactional5": "true", "transactional6": "false" }, "from": { "email": "*****@*****.**", "name": "Twilio SendGrid" }, "headers": { "X-Test10": "Test10", "X-Test11": "Test11", "X-Test12": "Test12", "X-Test9": "Test9" }, "ip_pool_name": "IP Pool Name", "mail_settings": { "bcc": { "email": "*****@*****.**", "enable": false }, "bypass_list_management": { "enable": false }, "footer": { "enable": true, "html": "<string>w00t!<strong>", "text": "w00t" }, "sandbox_mode": { "enable": true }, "spam_check": { "enable": true, "post_to_url": "https://example.com", "threshold": 5 } }, "personalizations": [ { "bcc": [ { "email": "*****@*****.**", "name": "Example User7" }, { "email": "*****@*****.**", "name": "Example User8" }, { "email": "*****@*****.**", "name": "Example User9" } ], "cc": [ { "email": "*****@*****.**", "name": "Example User4" }, { "email": "*****@*****.**", "name": "Example User5" }, { "email": "*****@*****.**", "name": "Example User6" } ], "custom_args": { "marketing1": "true", "marketing2": "false", "transactional1": "false", "transactional2": "true" }, "headers": { "X-Test1": "Test1", "X-Test2": "Test2", "X-Test3": "Test3", "X-Test4": "Test4" }, "send_at": 1461775051, "subject": "Sending with SendGrid is Fun 0", "substitutions": { "%city1%": "Example City 1", "%city2%": "Example City 2", "%name1%": "Example Name 1", "%name2%": "Example Name 2" }, "to": [ { "email": "*****@*****.**", "name": "Example User1" }, { "email": "*****@*****.**", "name": "Example User2" }, { "email": "*****@*****.**", "name": "Example User3" } ] }, { "bcc": [ { "email": "*****@*****.**", "name": "Example User16" }, { "email": "*****@*****.**", "name": "Example User17" }, { "email": "*****@*****.**", "name": "Example User18" } ], "cc": [ { "email": "*****@*****.**", "name": "Example User13" }, { "email": "*****@*****.**", "name": "Example User14" }, { "email": "*****@*****.**", "name": "Example User15" } ], "custom_args": { "marketing3": "true", "marketing4": "false", "transactional3": "false", "transactional4": "true" }, "headers": { "X-Test5": "Test5", "X-Test6": "Test6", "X-Test7": "Test7", "X-Test8": "Test8" }, "send_at": 1461775052, "subject": "Sending with SendGrid is Fun 1", "substitutions": { "%city3%": "Example City 3", "%city4%": "Example City 4", "%name3%": "Example Name 3", "%name4%": "Example Name 4" }, "to": [ { "email": "*****@*****.**", "name": "Example User10" }, { "email": "*****@*****.**", "name": "Example User11" }, { "email": "*****@*****.**", "name": "Example User12" } ] } ], "reply_to": { "email": "*****@*****.**", "name": "Twilio SendGrid Reply" }, "sections": { "%section1%": "Substitution for Section 1 Tag", "%section2%": "Substitution for Section 2 Tag", "%section3%": "Substitution for Section 3 Tag" }, "send_at": 1461775053, "subject": "Sending with SendGrid is Fun 2", "template_id": "13b8f94f-bcae-4ec6-b752-70d6cb59f932", "tracking_settings": { "click_tracking": { "enable": true, "enable_text": false }, "ganalytics": { "enable": true, "utm_campaign": "utm_campaign", "utm_content": "utm_content", "utm_medium": "utm_medium", "utm_source": "utm_source", "utm_term": "utm_term" }, "open_tracking": { "enable": true, "substitution_tag": "open_tracking" }, "subscription_tracking": { "enable": true, "html": "<strong>Goodbye!</strong>", "substitution_tag": "unsubscribe", "text": "Goodbye" } } }'''))
def test_dynamic_template_data(self): self.maxDiff = None to_emails = [ To(email='*****@*****.**', name='Example To 0 Name', dynamic_template_data=DynamicTemplateData( {'name': 'Example 0 Name'})), To(email='*****@*****.**', name='Example To 1 Name', dynamic_template_data={'name': 'Example 1 Name'}) ] message = Mail(from_email=From('*****@*****.**', '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": "*****@*****.**", "name": "Example From Name" }, "personalizations": [ { "dynamic_template_data": { "name": "Example 1 Name" }, "to": [ { "email": "*****@*****.**", "name": "Example To 1 Name" } ] }, { "dynamic_template_data": { "name": "Example 0 Name" }, "to": [ { "email": "*****@*****.**", "name": "Example To 0 Name" } ] } ], "subject": "Hi!" }'''))
## Send a Single Email to a Single Recipient import os import json from sendgrid import SendGridAPIClient from sendgrid.helpers.mail import Mail, From, To, Subject, PlainTextContent, HtmlContent, SendGridException message = Mail( from_email=From('*****@*****.**', 'DX'), to_emails=To('*****@*****.**', 'Elmer Thomas'), 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>')) try: print(json.dumps(message.get(), sort_keys=True, indent=4)) sendgrid_client = SendGridAPIClient( api_key=os.environ.get('SENDGRID_API_KEY')) response = sendgrid_client.send(message=message) print(response.status_code) print(response.body) print(response.headers) except SendGridException as e: print(e.message) # Send a Single Email to Multiple Recipients import os import json from sendgrid import SendGridAPIClient from sendgrid.helpers.mail import Mail, From, To, Subject, PlainTextContent, HtmlContent, SendGridException
def generate_email_subject(): return Subject('Errors in ML Accelerators Tests at {}'.format( datetime.now( pytz.timezone('US/Pacific')).strftime("%Y/%m/%d %H:%M:%S")))
def test_multiple_emails_to_multiple_recipients(self): from sendgrid.helpers.mail import (Mail, From, To, Subject, PlainTextContent, HtmlContent, Substitution) self.maxDiff = None to_emails = [ To(email='*****@*****.**', name='Example Name 0', substitutions=[ Substitution('-name-', 'Example Name Substitution 0'), Substitution('-github-', 'https://example.com/test0'), ], subject=Subject('Override Global Subject')), To(email='*****@*****.**', 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( from_email=From('*****@*****.**', 'Example From Name'), to_emails=to_emails, subject=Subject('Hi -name-'), plain_text_content=PlainTextContent( 'Hello -name-, your URL is -github-, email sent at -time-'), html_content=HtmlContent( '<strong>Hello -name-, your URL is <a href=\"-github-\">here</a></strong> email sent at -time-' ), global_substitutions=global_substitutions, is_multiple=True) self.assertEqual( message.get(), json.loads(r'''{ "content": [ { "type": "text/plain", "value": "Hello -name-, your URL is -github-, email sent at -time-" }, { "type": "text/html", "value": "<strong>Hello -name-, your URL is <a href=\"-github-\">here</a></strong> email sent at -time-" } ], "from": { "email": "*****@*****.**", "name": "Example From Name" }, "personalizations": [ { "substitutions": { "-github-": "https://example.com/test1", "-name-": "Example Name Substitution 1", "-time-": "2019-01-01 00:00:00" }, "to": [ { "email": "*****@*****.**", "name": "Example Name 1" } ] }, { "subject": "Override Global Subject", "substitutions": { "-github-": "https://example.com/test0", "-name-": "Example Name Substitution 0", "-time-": "2019-01-01 00:00:00" }, "to": [ { "email": "*****@*****.**", "name": "Example Name 0" } ] } ], "subject": "Hi -name-" }'''))
def SendEmails(HubPullRequest, EmailContents, SendMethod): if SendMethod == 'SMTP': # # Send emails to SMTP Server # try: SmtpServer = smtplib.SMTP(SMTP_ADDRESS, SMTP_PORT_NUMBER) SmtpServer.starttls() SmtpServer.ehlo() SmtpServer.login(SMTP_USER_NAME, SMTP_PASSWORD) Index = 0 for Email in EmailContents: Index = Index + 1 EmailMessage = email.message_from_string(Email) print('pr[%d] email[%d]' % (HubPullRequest.number, Index), '----> SMTP Email Start <----') print(Email) print('pr[%d] email[%d]' % (HubPullRequest.number, Index), '----> SMTP Email End <----') if 'From' in EmailMessage: try: FromAddress, FromName = ParseEmailAddress( EmailMessage['From']) except: print('Parsed From: Bad address:', EmailMessage['From']) FromAddress = '*****@*****.**' FromName = 'From %s via TianoCore Webhook' % ( HubPullRequest.user.login) else: print('Parsed From: Missing address:') FromAddress = '*****@*****.**' FromName = 'From %s via TianoCore Webhook' % ( HubPullRequest.user.login) ToList = [] if 'To' in EmailMessage: ToList = ToList + EmailMessage['To'].split(',') if 'Cc' in EmailMessage: ToList = ToList + EmailMessage['Cc'].split(',') try: SmtpServer.sendmail(FromAddress, ToList, Email) print('SMTP send mail success') except: print('ERROR: SMTP send mail failed') SmtpServer.quit() except: print( 'SendEmails: error: can not connect or login or send messages.' ) elif SendMethod == 'SendGrid': # # Send emails to SendGrid # Index = 0 for Email in EmailContents: Index = Index + 1 EmailMessage = email.message_from_string(Email) print('pr[%d] email[%d]' % (HubPullRequest.number, Index), '----> SendGrid Email Start <----') print(Email) print('pr[%d] email[%d]' % (HubPullRequest.number, Index), '----> SendGrid Email End <----') message = Mail() if 'From' in EmailMessage: try: EmailAddress, EmailName = ParseEmailAddress( EmailMessage['From']) message.from_email = From(EmailAddress, EmailName) except: print('Parsed From: Bad address:', EmailMessage['From']) message.from_email = From( '*****@*****.**', 'From %s via TianoCore Webhook' % (HubPullRequest.user.login)) else: print('Parsed From: Missing address:') message.from_email = From( '*****@*****.**', 'From %s via TianoCore Webhook' % (HubPullRequest.user.login)) UniqueAddressList = [] if 'To' in EmailMessage: for Address in EmailMessage['To'].split(','): try: EmailAddress, EmailName = ParseEmailAddress(Address) if EmailAddress.lower() in UniqueAddressList: continue UniqueAddressList.append(EmailAddress.lower()) message.add_to(To(EmailAddress, EmailName)) except: print('Parsed To: Bad address:', Address) continue if 'Cc' in EmailMessage: for Address in EmailMessage['Cc'].split(','): try: EmailAddress, EmailName = ParseEmailAddress(Address) if EmailAddress.lower() in UniqueAddressList: continue UniqueAddressList.append(EmailAddress.lower()) message.add_cc(Cc(EmailAddress, EmailName)) except: print('Parsed Cc: Bad address:', Address) continue message.subject = Subject(EmailMessage['Subject']) for Field in ['Message-Id', 'In-Reply-To']: if Field in EmailMessage: message.header = Header(Field, EmailMessage[Field]) message.content = Content(MimeType.text, EmailMessage.get_payload()) try: sendgrid_client = SendGridAPIClient(SENDGRID_API_KEY) response = sendgrid_client.send(message) print('SendGridAPIClient send success') time.sleep(1) except Exception as e: print('ERROR: SendGridAPIClient failed') else: Index = 0 for Email in EmailContents: Index = Index + 1 EmailMessage = email.message_from_string(Email) print('pr[%d] email[%d]' % (HubPullRequest.number, Index), '----> Draft Email Start <----') if 'From' in EmailMessage: try: EmailAddress, EmailName = ParseEmailAddress( EmailMessage['From']) print('Parsed From:', EmailAddress, EmailName) except: print('Parsed From: Bad address:', EmailMessage['From']) else: print('Parsed From: Missing address:') UniqueAddressList = [] if 'To' in EmailMessage: for Address in EmailMessage['To'].split(','): try: EmailAddress, EmailName = ParseEmailAddress(Address) if EmailAddress.lower() in UniqueAddressList: continue UniqueAddressList.append(EmailAddress.lower()) print('Parsed To:', EmailAddress, EmailName) except: print('Parsed To: Bad address:', Address) continue if 'Cc' in EmailMessage: for Address in EmailMessage['Cc'].split(','): try: EmailAddress, EmailName = ParseEmailAddress(Address) if EmailAddress.lower() in UniqueAddressList: continue UniqueAddressList.append(EmailAddress.lower()) print('Parsed Cc:', EmailAddress, EmailName) except: print('Parsed Cc: Bad address:', Address) continue print('--------------------') print(Email) print('pr[%d] email[%d]' % (HubPullRequest.number, Index), '----> Draft Email End <----')
def add_personalization(self, tos, subject, template_data, index): self.message.to = [To(to, '', p=index) for to in tos] self.message.subject = Subject(subject, p=index) self.message.dynamic_template_data = DynamicTemplateData(template_data, p=index)
import os import json import python_http_client from sendgrid import SendGridAPIClient from sendgrid.helpers.mail import Mail, From, To, Subject, PlainTextContent, HtmlContent, SendGridException API_KEY = 'Hn6D' TEMPLATE_ID = 'bf513' message = Mail(subject=Subject("my subject"), from_email=From('*****@*****.**', 'sender'), to_emails=To('*****@*****.**', 'Vitalii')) # message.template_id=TEMPLATE_ID # message.dynamic_template_data = {"unsubscribe": "<<< unsubscribe custom text >>>", "unsubscribe_preferences": "<<< unsubscribe_preferences custom text >>>"} message.content = PlainTextContent("this is test content") try: sendgrid_client = SendGridAPIClient(API_KEY) print(json.dumps(message.get(), sort_keys=True, indent=4)) response = sendgrid_client.send(message=message) if 300 > response.status_code >= 200: print(response.status_code) print(response.body) except SendGridException as e: print(e.message) except python_http_client.exceptions.HTTPError as e: print(e.body)
def build_kitchen_sink(): """All settings set""" from sendgrid.helpers.mail import ( Mail, From, To, Cc, Bcc, Subject, PlainTextContent, HtmlContent, SendGridException, Substitution, Header, CustomArg, SendAt, Content, MimeType, Attachment, FileName, FileContent, FileType, Disposition, ContentId, TemplateId, Section, ReplyTo, Category, BatchId, Asm, GroupId, GroupsToDisplay, IpPoolName, MailSettings, BccSettings, BccSettingsEmail, BypassListManagement, FooterSettings, FooterText, FooterHtml, SandBoxMode, SpamCheck, SpamThreshold, SpamUrl, TrackingSettings, ClickTracking, SubscriptionTracking, SubscriptionText, SubscriptionHtml, SubscriptionSubstitutionTag, OpenTracking, OpenTrackingSubstitutionTag, Ganalytics, UtmSource, UtmMedium, UtmTerm, UtmContent, UtmCampaign) import time import datetime message = Mail() # Define Personalizations message.to = To('*****@*****.**', 'Example User1', p=0) message.to = [ To('*****@*****.**', 'Example User2', p=0), To('*****@*****.**', 'Example User3', p=0) ] message.cc = Cc('*****@*****.**', 'Example User4', p=0) message.cc = [ Cc('*****@*****.**', 'Example User5', p=0), Cc('*****@*****.**', 'Example User6', p=0) ] message.bcc = Bcc('*****@*****.**', 'Example User7', p=0) message.bcc = [ Bcc('*****@*****.**', 'Example User8', p=0), Bcc('*****@*****.**', 'Example User9', p=0) ] message.subject = Subject('Sending with SendGrid is Fun 0', p=0) message.header = Header('X-Test1', 'Test1', p=0) message.header = Header('X-Test2', 'Test2', p=0) message.header = [ Header('X-Test3', 'Test3', p=0), Header('X-Test4', 'Test4', p=0) ] message.substitution = Substitution('%name1%', 'Example Name 1', p=0) message.substitution = Substitution('%city1%', 'Example City 1', p=0) message.substitution = [ Substitution('%name2%', 'Example Name 2', p=0), Substitution('%city2%', 'Example City 2', p=0) ] message.custom_arg = CustomArg('marketing1', 'true', p=0) message.custom_arg = CustomArg('transactional1', 'false', p=0) message.custom_arg = [ CustomArg('marketing2', 'false', p=0), CustomArg('transactional2', 'true', p=0) ] message.send_at = SendAt(1461775051, p=0) message.to = To('*****@*****.**', 'Example User10', p=1) message.to = [ To('*****@*****.**', 'Example User11', p=1), To('*****@*****.**', 'Example User12', p=1) ] message.cc = Cc('*****@*****.**', 'Example User13', p=1) message.cc = [ Cc('*****@*****.**', 'Example User14', p=1), Cc('*****@*****.**', 'Example User15', p=1) ] message.bcc = Bcc('*****@*****.**', 'Example User16', p=1) message.bcc = [ Bcc('*****@*****.**', 'Example User17', p=1), Bcc('*****@*****.**', 'Example User18', p=1) ] message.header = Header('X-Test5', 'Test5', p=1) message.header = Header('X-Test6', 'Test6', p=1) message.header = [ Header('X-Test7', 'Test7', p=1), Header('X-Test8', 'Test8', p=1) ] message.substitution = Substitution('%name3%', 'Example Name 3', p=1) message.substitution = Substitution('%city3%', 'Example City 3', p=1) message.substitution = [ Substitution('%name4%', 'Example Name 4', p=1), Substitution('%city4%', 'Example City 4', p=1) ] message.custom_arg = CustomArg('marketing3', 'true', p=1) message.custom_arg = CustomArg('transactional3', 'false', p=1) message.custom_arg = [ CustomArg('marketing4', 'false', p=1), CustomArg('transactional4', 'true', p=1) ] message.send_at = SendAt(1461775052, p=1) message.subject = Subject('Sending with SendGrid is Fun 1', p=1) # The values below this comment are global to entire message message.from_email = From('*****@*****.**', 'DX') message.reply_to = ReplyTo('*****@*****.**', 'DX Reply') message.subject = Subject('Sending with SendGrid is Fun 2') message.content = Content(MimeType.text, 'and easy to do anywhere, even with Python') message.content = Content(MimeType.html, '<strong>and easy to do anywhere, even with Python</strong>') message.content = [ Content('text/calendar', 'Party Time!!'), Content('text/custom', 'Party Time 2!!') ] message.attachment = Attachment(FileContent('base64 encoded content 1'), FileType('application/pdf'), FileName('balance_001.pdf'), Disposition('attachment'), ContentId('Content ID 1')) message.attachment = [ Attachment(FileContent('base64 encoded content 2'), FileType('image/png'), FileName('banner.png'), Disposition('inline'), ContentId('Content ID 2')), Attachment(FileContent('base64 encoded content 3'), FileType('image/png'), FileName('banner2.png'), Disposition('inline'), ContentId('Content ID 3')) ] message.template_id = TemplateId('13b8f94f-bcae-4ec6-b752-70d6cb59f932') message.section = Section('%section1%', 'Substitution for Section 1 Tag') message.section = [ Section('%section2%', 'Substitution for Section 2 Tag'), Section('%section3%', 'Substitution for Section 3 Tag') ] message.header = Header('X-Test9', 'Test9') message.header = Header('X-Test10', 'Test10') message.header = [ Header('X-Test11', 'Test11'), Header('X-Test12', 'Test12') ] message.category = Category('Category 1') message.category = Category('Category 2') message.category = [ Category('Category 1'), Category('Category 2') ] message.custom_arg = CustomArg('marketing5', 'false') message.custom_arg = CustomArg('transactional5', 'true') message.custom_arg = [ CustomArg('marketing6', 'true'), CustomArg('transactional6', 'false') ] message.send_at = SendAt(1461775053) message.batch_id = BatchId("HkJ5yLYULb7Rj8GKSx7u025ouWVlMgAi") message.asm = Asm(GroupId(1), GroupsToDisplay([1,2,3,4])) message.ip_pool_name = IpPoolName("IP Pool Name") mail_settings = MailSettings() mail_settings.bcc_settings = BccSettings(False, BccSettingsEmail("*****@*****.**")) mail_settings.bypass_list_management = BypassListManagement(False) mail_settings.footer_settings = FooterSettings(True, FooterText("w00t"), FooterHtml("<string>w00t!<strong>")) mail_settings.sandbox_mode = SandBoxMode(True) mail_settings.spam_check = SpamCheck(True, SpamThreshold(5), SpamUrl("https://example.com")) message.mail_settings = mail_settings tracking_settings = TrackingSettings() tracking_settings.click_tracking = ClickTracking(True, False) tracking_settings.open_tracking = OpenTracking(True, OpenTrackingSubstitutionTag("open_tracking")) tracking_settings.subscription_tracking = SubscriptionTracking( True, SubscriptionText("Goodbye"), SubscriptionHtml("<strong>Goodbye!</strong>"), SubscriptionSubstitutionTag("unsubscribe")) tracking_settings.ganalytics = Ganalytics( True, UtmSource("utm_source"), UtmMedium("utm_medium"), UtmTerm("utm_term"), UtmContent("utm_content"), UtmCampaign("utm_campaign")) message.tracking_settings = tracking_settings return message.get()
def send_email_base(self, from_email, to_emails, subject, html_content): message = Mail(from_email=From(from_email), to_emails=[To(to_email) for to_email in to_emails], subject=Subject(subject), html_content=HtmlContent(html_content)) return self.__sg.send(message)
def send_tracking_email(data, context): sg = sendgrid.SendGridAPIClient(api_key=os.environ['SENDGRID_API_KEY']) dt = datetime.datetime.now(pytz.timezone('US/Pacific')) print(data, context, dt) client = datastore.Client() groups_query = client.query( kind='group', filters=[('end_date', '>=', dt.date().isoformat()) ], # cannot have multiple filters!? ) for group in groups_query.fetch(): print(group) if dt.date().isoformat() < group['start_date']: continue tracking_cadence = group['tracking_cadence'] if tracking_cadence == 'weekly' and dt.weekday( ) != 6 and not IS_DEVELOPMENT: # sunday continue days_remaining = ( datetime.datetime.strptime(group['end_date'], '%Y-%m-%d').date() - dt.date()).days goals_query = client.query(kind='goal2', ancestor=group.key) goals = list(goals_query.fetch()) if not goals: print('no goals found for group {}'.format(group)) continue for goal in goals: print(goal) streak = compute_streak(goal) group_progress_since_my_last_completion = ( compute_group_progress_since_my_last_completion(goal, goals)) progress = len(goal.get('completions', [])) denominator = len(goal.get('opportunities', [])) opportunity = dt.date().isoformat() rendered = TEMPLATE_ENV.get_template("tracking_email.tmpl").render( **locals()) subject_prefix = '[DEV] ' if IS_DEVELOPMENT else '' if IS_DEVELOPMENT and DEVELOPER_EMAIL_STRING not in goal['email']: continue mail = Mail( from_email=From(email="*****@*****.**"), subject=Subject( subject_prefix + "Eccountabot {} {} ".format(group['name'], dt.date().isoformat()) + '🔥' * min(int(streak / 3), 5)), to_emails=To(email=goal['email']), html_content=Content("text/html", rendered)) try: response = sg.client.mail.send.post(request_body=mail.get()) except exceptions.BadRequestsError as e: print(e.body) raise if tracking_cadence == 'weekly': goal['last_week'] = goal.get('this_week', '') goal['this_week'] = '' goal['opportunities'] = list( set(goal.get('opportunities', []) + [opportunity])) client.put_multi(goals)
def send_summary_email(data, context): print(data, context) force_send = data.get('force_send', False) sg = sendgrid.SendGridAPIClient(api_key=os.environ['SENDGRID_API_KEY']) dt = datetime.datetime.now(pytz.timezone('US/Pacific')) client = datastore.Client() # cannot have multiple filters!? groups_query = client.query( kind='group', filters=[('end_date', '>=', (dt.date() - datetime.timedelta(days=1)).isoformat())], ) subject_prefix = '[DEV] ' if IS_DEVELOPMENT else '' for group in groups_query.fetch(): print(group) if dt.date().isoformat() < group['start_date']: continue final_summary_date = ( datetime.datetime.strptime(group['end_date'], '%Y-%m-%d').date() + datetime.timedelta(days=1) ).isoformat() is_final = dt.date().isoformat() == final_summary_date if not force_send and dt.weekday() != 0 and not is_final and not IS_DEVELOPMENT: continue goals_query = client.query( kind='goal2', ancestor=group.key ) goals = list(goals_query.fetch()) if not goals: print('no goals found for group {}'.format(group)) continue personalization = Personalization() total_progress = 0 total_denominator = 0 for goal in goals: print(goal) goal['denominator'] = len(goal.get('opportunities', [])) goal['progress'] = len(goal.get('completions', [])) goal['background-color'] = compute_goal_color(goal) goal['completed_last_week'] = False opportunities = goal.get('opportunities', []) if opportunities and max(opportunities) in goal.get('completions', []): goal['completed_last_week'] = True total_progress += goal['progress'] total_denominator += goal['denominator'] if IS_DEVELOPMENT and DEVELOPER_EMAIL_STRING not in goal['email']: continue personalization.add_to(To(email=goal['email'])) goals = sorted(goals, key=lambda x: x['progress'] / goal['denominator'], reverse=True) template = TEMPLATE_ENV.get_template("summary_email.tmpl") rendered = template.render(**locals()) mail = Mail( from_email=From(email="*****@*****.**"), subject=Subject(subject_prefix + "Eccountabot {}Summary {} {}".format( 'Final ' if is_final else '', group['name'], dt.date().isoformat() )), html_content=Content("text/html", rendered) ) mail.add_personalization(personalization) try: response = sg.client.mail.send.post(request_body=mail.get()) except exceptions.BadRequestsError as e: print(e.body) raise