Sending Bulk Emails With Twilio SendGrid and Python
Tags: twilio, email, python, sendgrid
Published: 2019-12-17 19:49:48

---
canonical_url: https://www.twilio.com/blog/sending-bulk-email-sendgrid-python
---

Sending a [single email](https://www.twilio.com/blog/how-to-send-emails-in-python-with-sendgrid) is great, but one of the big advantages of email is the ability to quickly reach a wide audience. Today I’ll show you how to send mass emails with Python and SendGrid. Just for fun, let’s say you’re a Python developer who works at a donut shop. You need a way of letting the customers who have signed up for your email list know when fresh donuts have come straight out of the oven. 🍩

## Prerequisites

- [Python 2 or 3](https://www.fullstackpython.com/python-2-or-3.html) installed. Since [it’s almost 2020](https://pythonclock.org/) I’d strongly recommend Python 3.
- A free SendGrid account - [sign up here](https://signup.sendgrid.com/).
- At least [two email addresses](https://www.google.com/gmail/about/), to test things out and make sure they’re working. You can sign up for (multiple) free Gmail addresses here. Or you can try the [old hack of adding a  + to your existing Gmail address](https://gmail.googleblog.com/2008/03/2-hidden-ways-to-get-more-from-your.html). Caveat: we ran into some deliverability issues there.

## Setting Up Your Python Development Environment

First, create a new Python project. If you need to brush up on general Python environment setup, [follow this useful guide](https://www.twilio.com/docs/usage/tutorials/how-to-set-up-your-python-and-flask-development-environment).

Create your API key from the [SendGrid dashboard](https://app.sendgrid.com/settings/api_keys). Let’s call it “bulk email.”

![Screenshot of the SendGrid UI for creating an API key. The key name is "bulk email" and the permissions are "full access."](https://thepracticaldev.s3.amazonaws.com/i/7mijkjfg6cof5wjr1ojp.png)

After clicking “Create & View”, you’ll see your key. Before you close this dialog box, [save the key in an environment variable](https://www.twilio.com/blog/2017/01/how-to-set-environment-variables.html) called `SENDGRID_API_KEY` since you won’t be able to get that same key from the SendGrid dashboard again for security reasons.

Install the Sendgrid Python helper library with `pip install sendgrid`. Create a file, `send_mail.py`, and open it in your editor of choice.

## Sending a single email to multiple recipients

Copy the following code into `send_mail.py`:

```python
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail

# Replace these with your email addresses and names
to_emails = [
    ('example1@mail.com', 'Steven Universe'),
    ('example2@mail.com', 'Garnet')
]

message = Mail(
    from_email=('sadie@thebigdonut.party', 'Sadie Miller'),
    subject='🍩 Donuts, at the big donut 🍩',
    html_content='<p>Fresh donuts are out of the oven. Get them while they’re <em>hot!</em></p>',
    # for improved deliverability, provide plain text content in addition to html content
    plain_text_content='Fresh donuts are out of the oven. Get them while they’re hot!',
    to_emails=to_emails,
    is_multiple=True)
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)
```

On your command line you’ll see some output resembling the following:

```bash
202
b''
Server: nginx
Date: Mon, 02 Dec 2019 23:44:46 GMT
Content-Length: 0
Connection: close
X-Message-Id: xxxx
Access-Control-Allow-Origin: https://sendgrid.api-docs.io
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Authorization, Content-Type, On-behalf-of, x-sg-elas-acl
Access-Control-Max-Age: 600
X-No-CORS-Reason: https://sendgrid.com/docs/Classroom/Basics/API/cors.html
```

![A screenshot of an email from "Sadie Miller" with the subject line "🍩 Donuts, at the big donut 🍩" and a body of "Fresh donuts are out of the oven. Get them while they're hot!"](https://thepracticaldev.s3.amazonaws.com/i/hu9wz64jlbpx0btsgka4.png)

Also, you should receive some emails in your inboxes.  If you don’t see it check your spam or promotions folder.

The current API rate limit is 1000 emails per request. Does your high-throughput, scalable, fault-tolerant donut shop have more customers than that? If yes you’ll need to split the email addresses into lists of less than 1000 and make multiple calls to the `send` method.

Recipients of this email won’t be able to see one another’s email addresses. If you want to send multiple email addresses but keep the recipients addresses visible to one another, use the same code as above but remove the `is_multiple` parameter from line 18. That said, **be careful and don’t expose your customers’ email addresses unless you have a good use case for doing so**.

## Personalizing mass emails

If you’re a good donut shop owner, you’ve been paying attention to your customers. You noticed that Steven really loves bacon donuts.

With personalizations, you can change the emails you send to your customers to make them more, well, *personal*. Like mentioning their favorite kind of donut in the subject line to entice them to come in.

Replace the code you’ve got in `send_mail.py` with the following:

```python
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
from sendgrid.helpers.mail import To

# Replace these with your email addresses and names
to_emails = [
    To(email='example1@mail.com’,
       name='Steven',
       substitutions={
           '-name-': 'Steven',
       },
       subject='Hi -name-, got BACON DONUTS? 🥓🥓🥓'),
    To(email='example1@mail.com’,
       name='Garnet'),
]

message = Mail(
    from_email=('sadie@thebigdonut.party', 'Sadie Miller'),
    to_emails=to_emails,
    subject='🍩 Donuts, at the big donut 🍩',
    html_content='<p>Fresh donuts are out of the oven. Get them while they’re <em>hot!</em></p>',
    plain_text_content='Fresh donuts are out of the oven. Get them while they’re hot!',
    is_multiple=True)

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)
```

Run `python send_mail.py` to test it out. If a personalized subject line isn’t supplied for a particular recipient, we fall back to the default. You should have received one email with a bacon subject line and one with a generic subject line.

![Screenshot of an email from "Sadie Miller" with the subject line "Hi Steven, got BACON DONUTS? 🥓🥓🥓" and the body "Fresh donut are out of the oven. Get them while they're hot!"](https://thepracticaldev.s3.amazonaws.com/i/9ycjc8j982xs2tim7lm2.png)

The personalizations API can do more than change the subject line. Here’s the [list of email attributes that can currently be personalized](https://sendgrid.com/docs/API_Reference/api_v3.html):
- `subject`: the email subject line.
- `headers`: any headers you want to send with the email.
- `substitutions`: key/value pairs representing strings that you would like to substitute into an email subject line or body.
- `custom_args`: any custom arguments you would like to include in your email that will override substitutions.
- `send_at`: specifies a particular time you’d like the email to be sent, in Unix timestamp format.

## Wrapping up our Python SendGrid bulk email adventure

Let’s review what we’ve learned today:
- How to send a single SendGrid email to multiple recipients, without ccing
- How to send a single SendGrid email and cc multiple recipients
- How to use personalizations to customize emails to multiple recipients

Give yourself a reward, you’ve earned it. 🎉 If you’re craving donuts now, sorry not sorry.

The SendGrid API is so full-featured and flexible that it’s impossible to fit everything it can do into one blog post. For the most up to date information, [check out the SendGrid docs](https://sendgrid.com/docs/API_Reference/api_v3.html). You can also look at the open source code for the [Python helper library](https://pypi.org/project/sendgrid/) which is [available on GitHub](https://github.com/sendgrid/sendgrid-python/). Thanks for reading, and happy emailing.