Three Ways to Send Emails Using Python With Code Tutorials
Tags: python, ux
Published: 2021-08-11 20:29:12

For software products of every scale, emails are the de facto standard for notifying your users. It’s a fast, cost-effective, and readily accessible channel for reaching your users, especially if you’re sending transactional emails or generating event-driven alerts. 

In this post, I’ll go over three ways to send emails with Python. Apps can leverage Python for sending emails for an array of use cases. For example, you can generate alarms if things go south in production, send confirmation emails to new users, or notify users of new activity in your app. 

##3 ways to send emails from your Python app
There are three main options for sending email with Python: SMTP, a transactional email service, and a multichannel notifications service.

Below, I’ll review the pros and cons for each option. Then, in the next section, I’ll walk you through three different code tutorials for using each option to send emails with Python.

###1. Using SMTP
Python has a built-in module for sending emails via SMTP, which makes getting started with email a piece of cake.

####Pros of using SMTP
Easy to set up

Highly cost-effective

Platform agnostic

####Cons of using SMTP
Less secure

No built-in analytics

Longer send times

Long-term maintenance and uptime burden

###2. Using a transactional email service
You can also easily integrate third-party [transactional email APIs](https://www.courier.com/blog/best-transactional-email-api-service) like [SendGrid](https://sendgrid.com/), [Mailgun](https://www.mailgun.com/), and [AWS SES](https://aws.amazon.com/ses/). If you are planning to send a high volume of emails or need to ensure deliverability, a hosted email API can be a great option and many providers offer a free or low-cost plan to start.

####Pros of transactional email services
Feature-rich, e.g. analytics

High email delivery rates

Better email delivery speeds

Scalability and reliability

####Cons of transactional email services
Learning curve for new API

Dependent on third-party intermediary

###3. Using a multichannel notifications service
Finally, if you’re planning to notify users on more than one channel, you can use a multichannel notifications service. [Courier](https://www.courier.com/), for example, gives you one uniform API to notify users over email, SMS, push, and chat apps like Slack and WhatsApp. Plus, you’ll get a drag-and-drop template builder and real-time logs and analytics for all your channels.

Even if you’re only sending emails today, multichannel notifications services can save you time and money. With a platform like Courier, you can easily add new channels, switch email service providers, or even add backup providers without writing any additional code. You get a complete notifications system that can scale with your product’s growth.

####Pros of multichannel notifications services
Single API for multiple channels

Easy to manage cross-channel delivery

Less code to write and maintain

####Cons of multichannel notifications services
Additional third-party intermediary

##Tutorial: How to send emails using SMTP in Python
You can use Python’s [built-in `smtplib` module](https://docs.python.org/3/library/smtplib.html) to send email using SMTP (Simple Mail Transfer Protocol), which is an application-level protocol. Note that the module makes use of [RFC 821](https://tools.ietf.org/html/rfc821) protocol for SMTP. I’ll show you how to use Gmail’s SMTP server for this walkthrough. 

1. Set up a Gmail account for sending your emails. Since you’ll be feeding a plaintext password to the program, Google considers the SMTP connection less secure. 

2. Go to the account settings and [allow less secure apps](https://myaccount.google.com/lesssecureapps) to access the account. As an aside, Gmail doesn't necessarily use SMTP on their internal mail servers; however, Gmail SMTP is an interface enabled by Google's smtp.gmail.com server. You might find smtp.gmail.com in email clients like Thunderbird, Outlook, and others.

3. Import `smtplib`. Since Python comes pre-packaged with `smtplib`, all you have to do is create a Python file and import `smtplib` into it. 

4. To create a secure connection, you can either use `SMTP_SSL()` with 465 port or `.starttls()` with 587 port. The former creates an SMTP connection that is secured from the beginning. The latter creates an unsecured SMTP connection that is encrypted via `.starttls()`.

To send email through `SMTP_SSL()`:

```javascript
import smtplib

gmail_user = 'your_email@gmail.com'
gmail_password = 'your_password'

sent_from = gmail_user
to = ['person_a@gmail.com', 'person_b@gmail.com']
subject = 'Lorem ipsum dolor sit amet'
body = 'consectetur adipiscing elit'

email_text = """\
From: %s
To: %s
Subject: %s

%s
""" % (sent_from, ", ".join(to), subject, body)

try:
    smtp_server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
    smtp_server.ehlo()
    smtp_server.login(gmail_user, gmail_password)
    smtp_server.sendmail(sent_from, to, email_text)
    smtp_server.close()
    print ("Email sent successfully!")
except Exception as ex:
    print ("Something went wrong….",ex)
```


To send email through `.starttls()`:

```javascript
import smtplib 
try: 
    #Create your SMTP session 
    smtp = smtplib.SMTP('smtp.gmail.com', 587) 

   #Use TLS to add security 
    smtp.starttls() 

    #User Authentication 
    smtp.login("sender_email_id","sender_email_id_password")
    
    #Defining The Message 
    message = "Message_you_need_to_send" 
    
    #Sending the Email
    smtp.sendmail("sender_email_id", "receiyer_email_id",message) 

    #Terminating the session 
    smtp.quit() 
    print ("Email sent successfully!") 

except Exception as ex: 
    print("Something went wrong....",ex) 
```

Now that you've initiated a secured SMTP connection, you can move forward and write your message and pass to `.sendmail()`.

##Tutorial: How to send emails using a transactional email service in Python
If you need to send a high volume of transactional emails or optimize deliverability, consider using a [transactional email service](https://www.courier.com/blog/best-transactional-email-api-service). There are many to choose from, including Amazon SES, Mailgun, and Postmark, and the vast majority support Python. 

In this tutorial, I’m going to use [SendGrid](https://sendgrid.com/), one of the most popular email APIs. What sets a service like SendGrid apart from SMTP are the out-of-the box features. SendGrid offers easy integration with a simple API, email analytics, round-the-clock support, and high deliverability rates.

Setting up SendGrid with Python is a fairly simple process:

Create an [account with SendGrid](https://signup.sendgrid.com/). SendGrid’s free plan includes 100 emails per day.

Generate and store a SendGrid API key and provide full access to *Mail Send* permissions.

Create a Python script and start using the API.

To begin using SendGrid’s API via Python, follow these steps: 

1. To install the `sendgrid` package on your machine, refer to SendGrid's [GitHub installation guide](https://github.com/sendgrid/sendgrid-python) or directly install via `pip install sendgrid`.

2. To use the package in a Python script:

```javascript
import sendgrid
import os
from sendgrid.helpers.mail import Mail, Email, To, Content
```


3. To assign your API key to the SendGrid API client:

```javascript
my_sg = sendgrid.SendGridAPIClient(api_key = os.environ.get('SENDGRID_API_KEY'))
```

4. To send email, create the body and generate JSON representation. Refer to SendGrid’s complete code block:

```javascript
import sendgrid
import os
from sendgrid.helpers.mail import Mail, Email, To, Content

my_sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY'))

# Change to your verified sender
from_email = Email("your_email@example.com")  

# Change to your recipient
to_email = To("destination@example.com")  

subject = "Lorem ipsum dolor sit amet"
content = Content("text/plain", "consectetur adipiscing elit")

mail = Mail(from_email, to_email, subject, content)

# Get a JSON-ready representation of the Mail object
mail_json = mail.get()

# Send an HTTP POST request to /mail/send
response = my_sg.client.mail.send.post(request_body=mail_json)
```

Note that you can easily set up SendGrid and send up to 10,000 exclusive mail requests every second with your Django and Flask web applications.

##Tutorial: How to send emails using a multi-channel notifications service in Python
If you’re looking to scale your application’s notification capabilities while keeping your codebase clean, you should consider a multichannel notifications service like Courier. Courier allows you to bring your own email provider, including support for SMTP and most popular transactional email APIs. 

I’ll walk you through setting up [Courier](https://www.courier.com/) and sending notifications in the following steps. I’ll use the same SendGrid account that we set up in the prior tutorial.

1. [Sign up for Courier](http://courier.com/register) and navigate to the *Designer* tab on the left.

![Courier's Designer Tab](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n8e5atkjof2uc33v93xt.png)

2. Click "Create Notification". Now you’re ready to integrate a provider for email. Courier supports direct integrations with a number of popular email providers such as SendGrid, Postmark, MailChimp Transactional, and more. For this tutorial, let’s go with SendGrid.

![Create Notification in Courier's Design Hub](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mpqp3qkft6jvga72jmjr.png)

3. To integrate with the channel of your choice, click "+ Add Channel". Once you’ve added your configured SendGrid integration, you can start adding content.

![Add a Channel in Courier's Dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o3xxtgfrfpsvgyrywiz5.png)

4. To design your notification, just drag and drop the template blocks. You can also add custom code to your notification, either by overriding the entire email or by adding a code block. If you decide to send your notification over another channel, you can reuse the same template blocks and Courier will take care of updating the formatting.

5. With your Courier account configured, create a Python script. You can download [Courier’s Python Package](https://github.com/trycourier/courier-python) via `pip install trycourier`.

6. Once you’ve published your notification, Courier will automatically generate a code snippet for you to use. Copy-paste the code snippet and make an API call with the following script:

```javascript
from trycourier import Courier 

client = Courier(auth_token="Courier_Authentication_Token")

response = client.send( 
    event="your-notification-id" #Your notification ID from Courier 
    recipient="your-recipient-id" #Usually your system's User ID
    profile={ 
        "email": "user@example.com" #The recipient’s email address
    }, 
    data={ 
        "Loredm Ipsum": "dolor sit amet" #Tthe message you wish to send 
    }
)

print(response['messageId'])
```

How to send emails with attachments in Python
To include attachments with in your email notifications, you can add an optional 'override' parameter as follows:

```javascript
from trycourier import Courier 

client = Courier(auth_token="Courier_Authentication_Token")

response = client.send( 
    event="your-event-id", 
    recipient="your-recipient-id", 
    profile={ 
        "email": "recipient_id",
        "phone_number": "recipient_number"
    }, 
    data={ 
        "Loredm Ipsum": "dolor sit amet" 
    },
    override={} #Pass the override here
)
print(response['messageId'])
```

Pass the following override to the override parameter to equip your emails with attachment functionality:

```javascript
"override": {
    “channel”: {
      “email”: {
        "attachments": [
          {
            "filename": "sample_file.txt",
            "contentType": "text/plain",
            "data": "SGk="
          }
        ]
      }
    }
}
```
##Wrapping it up
This article was essentially three tutorials in one, covering methods for sending emails with Python via SMTP, a transactional email service (SendGrid), and a multichannel notifications service (Courier). With basic Python knowledge, you should now be able to choose your preference among the three solutions and easily extend your web application’s functionality when it comes to transactional emails and notifications.

Author: Milan Bhardwaj