Send Dynamic Emails with Python and Twilio SendGrid
Time to read: 9 minutes
Email is a critical part of any business communication strategy, both internally and externally. Today the need to have dynamic, content-driven, responsive email campaigns is critical. Twilio SendGrid allows organizations to deliver on this need with a highly performant and customizable CRM that works well in both the GUI and programmatically via API.
In this tutorial, we’ll set up a free SendGrid account and, using Python, send ourselves both simple text/html emails as well as high-res, dynamic content. We’ll also retrieve sending data like the number of emails sent, how many were opened or clicked, if any bounced, etc.
By the end of the tutorial you’ll be able to:
- Set up a free SendGrid account and API key for interacting with the service
- Set up a Python application that calls the SendGrid Web API v3, sends emails to different lists, and retrieves statistics about those sends
- Start working with SendGrid as a CRM and deliver prebuilt, customized email campaigns to targets programmatically
Requirements:
- Python 3.6 or later - if your operating system doesn’t have a Python interpreter, you can go to python.org to download an installer
- A text editor or IDE - I preferVisual Studio Code which is super lightweight and has a ton of great extensions but there’s alsoAtom,Notepad++ and lots more
- A SendGrid account - if you’re new to Twilio/SendGrid create a free account or, if you already have an account, log in
Set Up Your SendGrid account and API key
Once you’ve signed up for SendGrid, log in and access your SendGrid Dashboard. From here we’ll set up our API key by clicking the caret by “Email API” and then “Integration Guide”:
Choose “Web API” on the next step:
And choose Python on the next page:
Click the blue “Create Key’ button on the next screen:
Once you have your key value, store it securely in your environment as “SENDGRID_API_KEY” as detailed in step 3 on the page. For MacOS and Linux users:
If you are using Windows:
Refer here if you want to create the Windows variable through the UI.
Once you’ve got your key stored securely, you’re ready to get started. You can follow the rest of the directions on the page in steps 4 and 5 to install the SendGrid pip package and send a test email if you like, but I recommend you follow along with the tutorial to create a virtual environment and keep your code and dependencies together.
Create a Python virtual environment
Now let’s create a Python virtual environment for our project and install the SendGrid Web API helper library:
For Linux and MacOS:
For Windows:
Send a Test Email
Now we’re ready to write some code and send ourselves a test email from SendGrid. Paste the code below in your text editor in a file called SendEmail.py
:
Our code above does the following:
- We import the
os
library to get to our environment variables and also the ‘Mail’ module from the SendGrid helper library - We define a function,
SendEmail
that takes one parameter, an email address. With that email address we create amessage
object and provide values for thefrom_email
,to_email
,subject
, andhtml_content
arguments - Then we create an instance of the
SendGridAPIClient
object, pass it our key, and call thesend()
method with our message object passed in - Finally we assign and print out our various response objects and a success or error message.
You can replace the URL in the anchor tag in html_content
with whatever you want; your website, Github, or leave it set to Google. It’s important to have a link to click on so that then we can check our clicks
statistics. High open/click-through rates are the ultimate goal of any email campaign.
There are a multitude of parameters you can play with as we’re going to see, but I recommend you leave FROM_EMAIL
set to some version of yourname@sendgridtest.com. That gives you a better chance for good deliverability and helps your emails to not look like spam to email domain monitoring systems. Sender Reputation is a big deal!
Once you’re ready, run the code either in the IDE or through the command line and input an email address you monitor (note that deliverability may vary by domain/email provider, more on that later). If successful, you should receive your email (fast!) and see something like the following in the console:
Success!
Sending Multiple Emails With Addressing Tags
The code examples that follow next will send out two emails by default but can be altered to send out many more, easily. I suggest you use plus addressing (also called address tags) to ensure you keep your Sender Reputation high.
Tag sare great for testing because they’re free and easy to create, simply add +1 (and then +2, +3, etc.) before your domain (@example.com) as necessary. This allows you to receive multiple emails on a single email address, thereby minimizing your chances of receiving a complaint or being flagged as spam. If you add multiple recipients to any script for testing, make sure you use address tags properly.
Sending Customized HTML Emails
You can see from the above that it’s fast and easy to customize simple HTML emails with variables, links, etc. While most campaigns focus a large amount of time on dynamic content, HTML emails still have value. For example, below is a script that will deploy customized HTML emails. Customization is achieved via the use of the substitutions
and subject
parameters. Place this in a file called SendHTML.py
:
SendHTML
takes a list of To
objects and sends each a message. Before you run this script replace your email address in the TO_EMAILS
list.
Structured as is, the script will send out two emails every time it is run, and you should note we’ve set the is_multiple
parameter of the Mail
object to True
to facilitate this. You can change the custom parameters, add more, and also add more recipient To
objects, just be careful how much and who you send to.
Sending Dynamic Content to Multiple Emails
Let’s continue to improve our emails. Any good email marketing campaign needs to be extensible and customizable to be successful. SendGrid allows both via the UI and the API. For this next part, you’ll need to log back into SendGrid and set up some dynamic, pre-built templates that will make our emails look great on whatever device they’re viewed.
Log into SendGrid and click under “Email API” again, then select “Dynamic Templates”:
On the next screen, click the blue “Create a Dynamic Template” button and name your template whatever you like:
Once you have it created, click the caret next to your template’s name to expand the frame and note the “Template ID” in the window corner, we’ll need it for our API calls later:
Click the “Add Version” button to begin creating our template. On the “Select a Design” page, you’ll see SendGrid’s pre-built dynamic templates. Hover over your favorite and click “Select”:
On the next page, select the recommended “Design Editor” for an intuitive drag and drop experience. However, if you’re proficient, you can edit the HTML as well:
You should see a pop up success message and a WYSIWYG design editor. Editing the HTML/content of these emails is beyond the scope of this tutorial but is entirely possible through the editor. You can also test your email from here for rapid design feedback. For our purposes, we want to set a few elements in your email: first make sure a you pick a frame and edit its URL property as below:
(Almost everything in the email frame has properties, so you can set as many as you like with links and use custom variables like below.)
Click into the text in any module and add the following placeholders or replace text with them:
Example:
Finally, hit “Save” in the upper bar and then hit back to make sure you have a new template with a green “ACTIVE” by it as well as the “Template ID” from earlier:
Now let’s refactor our code a bit and extend it to take advantage of this template and some of SendGrid’s other features. Place this in a file called SendDynamic.py
:
Our SendDynamic
function looks similar to SendHTML
, but will deploy the slick dynamic email we just created in the UI. You’ll also note we’re still passing some custom values: subject
, place
, and event
. These correspond to our HTML placeholders and will appear in the text blocks you edited earlier. We set our message
object’s template_id
to our dynamic template id from the UI and send as usual.
Send away and check out your emails. Be sure to view the Dynamic email on multiple devices to see how it looks good on anything. This also lets us record more metadata.
Sending Data - Opens, Clicks, Bounces and More
Sending out dynamic, customizable emails at blazing speeds is cool but we also want to know how our campaigns are performing so that we can adjust for maximum throughput. We want to know, amongst many other things, did people open the email, did they click, and did anyone bounce or get blocked? All this sending data is critical not only for our campaign but also for our Sender Reputation.
Let’s write some more code to call the SendGrid Statistics APIs and retrieve our sending data. Place this in a file called GetSendData.py
:
The code above:
- Makes three GET calls to the global statistics, mailbox, and browser API endpoints
- Retrieves the send data from each API and appends it to a list object and
- Writes that data to a file called
SendData.txt
at the end of the calls
You can (and should) change the parameter bodies at the top of the file, especially start_date
and end_date
. Set these to dates you know you will return data (like when you are doing this tutorial).
If you review your SendData.txt
file, you’ll see a detailed breakdown of your sends; how many got delivered/opened/clicked, which domains were sent to, and a breakdown of devices and browsers. All great stuff to know to tweak your campaign. You’ll also see parts of the parameter bodies (specifically the mailbox and browser headers) commented out; you can uncomment and replace these with specific mailbox/device values to filter your results to just those domains or devices. These APIs are extremely consistent and there are far more than what we are calling here, check out the docs for more information.
Putting it All Together
Let’s add one last piece of functionality to email our statistics to ourselves as an attachment. That way we’ve got a simple (but complete) email deployment system. You can place this in a file called EmailSendData.py
:
This code is pretty similar to our mailing code with the exception of the attachment piece. We add an attachment object, set its various properties, and point it to our ‘SendData.txt’ file. The most important part to understand here is we must read the data from our ‘SendData.txt’ file and then encode that by passing it to the ‘base64’ class. This is necessary for the attachment to be processed properly, see this section on the Request Body for more information.
Finally we can add the above to our already existing codebase with a minor tweak where GetSendData.py
will now ask the user if they want the sending data emailed to them:
With everything in place, you can start testing things out! Send yourself HTML or Dynamic emails, change names, subject lines, or content, and pull your sending data and have it delivered to you so you can see how your (test) emails are doing. SendGrid has a great UI for getting a high level view of your campaign, but for analytics and reporting it’s always good to pull from the source API to have all the details.
Wrap-up, Cautions about Email Sending, and Next Steps
I hope you had as much fun making this as I did. SendGrid is a highly versatile and robust platform and there are many customizations and options I didn’t get a chance to cover when writing this. I encourage you to start playing around with programmatic emails.
However, before you have too much fun, it’s important to keep in mind that Email sending is a highly monitored practice as it is so easy to deploy spam emails. It’s fast and simple to send a large amount of emails very quickly. In the Digital Age, emails will often be blocked by mailbox domain monitoring systems for anything resembling spam: a misspelled preheader, suspicious ‘from_email’, attached executable content, etc.
You may have noticed some of your emails not being delivered based on the email provider. This is all related to the highly regulated world of Email Spam. You should keep your Sender Reputation in mind at all times! It will highly influence the success of any production email campaigns you undertake. Again, this is the main reason for email address tags as they limit your risk footprint. You can also take a look at IP Warming to learn how to gain sender reputation and raise your delivery rate.
With those cautions in mind, head over to the SendGrid docs and start checking out all the other cool features. There’s a ton of great APIs to leverage and you can combine them with other Twilio services to build some really cool stuff! Thanks for reading!
James Putterman is an Integration Data Architect and Full Stack Developer in Kansas City, reach out on LinkedIn and Twitter to connect.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.