diff --git a/USE_CASES.md b/USE_CASES.md index 14619413a..4393d4670 100644 --- a/USE_CASES.md +++ b/USE_CASES.md @@ -4,6 +4,7 @@ This documentation provides examples for specific use cases. Please [open an iss * [Transactional Templates](#transactional_templates) * [Attachment](#attachment) +* [Asynchronous Mail Send](#asynchronous-mail-send) # Transactional Templates @@ -169,3 +170,88 @@ print(response.status_code) print(response.body) print(response.headers) ``` + + +# Asynchronous Mail Send + +## Using `asyncio` (3.5+) + +The built-in `asyncio` library can be used to send email in a non-blocking manner. `asyncio` helps us execute mail sending in a separate context, allowing us to continue execution of business logic without waiting for all our emails to send first. + +```python +import sendgrid +from sendgrid.helpers.mail import * +import os +import asyncio + + +sg = sendgrid.SendGridAPIClient( + apikey=os.getenv("SENDGRID_API_KEY") +) + +from_email = Email("test@example.com") +to_email = Email("test1@example.com") + +content = Content("text/plain", "This is asynchronous sending test.") + +# instantiate `sendgrid.helpers.mail.Mail` objects +em1 = Mail(from_email, "Message #1", to_email, content) +em2 = Mail(from_email, "Message #2", to_email, content) +em3 = Mail(from_email, "Message #3", to_email, content) +em4 = Mail(from_email, "Message #4", to_email, content) +em5 = Mail(from_email, "Message #5", to_email, content) +em6 = Mail(from_email, "Message #6", to_email, content) +em7 = Mail(from_email, "Message #7", to_email, content) +em8 = Mail(from_email, "Message #8", to_email, content) +em9 = Mail(from_email, "Message #9", to_email, content) +em10 = Mail(from_email, "Message #10", to_email, content) + + +ems = [em1, em2, em3, em4, em5, em6, em7, em8, em9, em10] + + +async def send_email(n, email): + ''' + send_mail wraps SendGrid's API client, and makes a POST request to + the api/v3/mail/send endpoint with `email`. + Args: + email: single mail object. + ''' + try: + response = sg.client.mail.send.post(request_body=email.get()) + if response.status_code < 300: + print("Email #{} processed".format(n), response.body, response.status_code) + except urllib.error.HTTPError as e: + e.read() + + +@asyncio.coroutine +def send_many(emails, cb): + ''' + send_many creates a number of non-blocking tasks (to send email) + that will run on the existing event loop. Due to non-blocking nature, + you can include a callback that will run after all tasks have been queued. + + Args: + emails: contains any # of `sendgrid.helpers.mail.Mail`. + cb: a function that will execute immediately. + ''' + print("START - sending emails ...") + for n, em in enumerate(emails): + asyncio.async(send_email(n, em)) + print("END - returning control...") + cb() + + +def sample_cb(): + print("Executing callback now...") + for i in range(0, 100): + print(i) + return + + +if __name__ == "__main__": + loop = asyncio.get_event_loop() + task = asyncio.async(send_many(ems, sample_cb)) + loop.run_until_complete(task) +``` \ No newline at end of file