Sending Emails with Python is too easy?
Published: 2024-04-21 20:06:41

Have you ever tried to make a Python project that can send you emails? Well, that's ez!

## Sending Emails with Python
You tried several mailing service. SMTPLib? No, it did not work (to me too). MailGun? It is not always free.

Google Accounts used to have **Less Secure Access**, which was recently removed. However, in addition, they added a **Gmail API** which is more secure as well as with good functionallities.

I'll be demonstrating you step-by-step to how to use Python to send emails. 

At the **Conclusion** section, you can see a project I made that also uses this Gmail API for verifying emails when you register on the website.

## Setting up
Like always, a terminal and
```bash
virtualenv .venv
source .venv/source/activate
```

Boom!

## Setting up the project
Go to GCP and create new project <https://console.cloud.google.com/projectcreate>


![Make a project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jep83ujz34tqi7itfevh.png)

Once it's created, select it. From the sidebar, go to **APIs & Services, Library** and enable the Gmail API.


![API Library](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c9t1xvjtwdxnbxsdmqhj.png)


![Enable Gmail API(https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6o1649vh90h039kt3q8d.png)

Then, you should see like this, asking you that **you may need credentials**. We do not need to create credentials from here. Just verify that you are at a similiar screen as me.


![Gmail API is now enabled](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qhgjdxefk4on1uzy8tgu.png)

Go to OAuth Consent screen, and choose **User Type** as **External**. 


![OAuth Info](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oz1ar1y6qxvkubwo3s03.png)

You will have to specify things like:
- App Name
- User Support Email
- App Logo
- Developer's Email Address

Specify them as you wish. Application's home page, privacy policy, TOC etc is optional.

> Any info you are specifying out of these are not shared. Even the app name does not make a difference, it is only what you will see when you are authenticating, not your users.

Add your email to user support and developer's email. You can specify app name like **My Newsletter**, it does not matter or change something worth.

### Continue
Leave scopes as it is, and add your email (or the email you will use as your email sender, **the from: email address**, like maybe a test account's email address to it).

> I recommend you to not use your main or valuable email address as a test user, or do not authenticate with it as Google auto-spam might report you. 

![For testing mode, only 100 test users can  be allowed.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qkp64b90l3rdnvh8r5cq.png)

### OAuth created

![OAuth created](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e0ctekonl2gvn7fbtqe2.png)

Scroll down and verify you added your test account (the email address of the google account you own that you will be using as the email sender) is there, or add it.

> You can publish your app however **there is no need** if you are doing this for your own. Additionally, they may ask you some questions so  its fine in testing.


![Go to credentials](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kz87dfvglvbw6f52kl3i.png)

Go to credentials and click create credentials, choose **OAuth Client ID** and then...

![Create credentials for a desktop application](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p81pd2f7c4qzhrhuh0oe.png)

The name is not shown to anyone except you so it's just fine as it is. Click CREATE.

![Credentials have been created](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kckzpzyjyb7k0zfv7s00.png)

Now as your credentials are created, download and save them to your project's directory as `credentials.json`.

## The coding
Create a file named `app.py` in your project folder. Your project should be like this:


![Folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1jm87dk363l20dfp7ad.png)

First, install the following libraries (make a requirements.txt and install from it, if you prefer):
- `google-api-python-client`
- `google-auth-httplib2`
- `google-auth-oauthlib`
- `requests`

### The python script
This is your magical weapon to send emails! Put this code in your `app.py`, confirming that you have a `credentials.json` in the same directory and you installed all the packages.

```python
import base64
import os.path
import pickle
from email.mime.text import MIMEText

from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from requests import HTTPError

SCOPES = ["https://www.googleapis.com/auth/gmail.send"]


def email(to, subject, body):
	creds = None
	if os.path.exists('token.pickle'):
		with open('token.pickle', 'rb') as token:
			creds = pickle.load(token)
	if not creds or not creds.valid:
		if creds and creds.expired and creds.refresh_token:
			creds.refresh(Request())
		else:
			flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)
			creds = flow.run_local_server(port=0)
		with open('token.pickle', 'wb') as token:
			pickle.dump(creds, token)

	service = build('gmail', 'v1', credentials=creds)
	message = MIMEText(body, 'html')
	message['to'] = to
	message['subject'] = subject
	create_message = {'raw': base64.urlsafe_b64encode(message.as_bytes()).decode()}
	try:
		message = (service.users().messages().send(userId="me", body=create_message).execute())
		return True
	except HTTPError as error:
		return False

```

> _I took this code lying on the surface of the web_

Great. At the last, add few lines to test our application. Call the `email` method with `to` as your email (the destination) and some dummy subject and body (body allows HTML).

```python
sendMyEmail = email(to="your_email_here@gmail.com", subject="Hi there bro!", body="What a <b>nice</b> day!")
if sendMyEmail:
  print("Email sent successfully. Check your inbox!")
else:
  print("Sorry, I cannot send the email.")
```

> The email will not be sent on errors like **Address Not Found** or something, so try to set the `to` email to a account you own and then see.

### Test the app
Finally, run the file.

![Authorize needed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fmiz6sdp08k2fyf0t0yv.png)

It should open a browser window and give you a URL to authorize. This is only needed to be done once as your token will be saved to `token.pickle`. **Please add `token.pickle` to your `.gitignore` as it may leak access to your account**.

Complete the authorization procedure with your testing account **(the account will only work if it is in the Testing Users list for the OAuth app)**.


![Security warning](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v49cgbtok9v9fn6ojden.png)

As you can see, you will be warned by Google as this app is on testing. We can continue as because we know what we are doing.


![Permissions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g8sps8lrd9eskyaugnf6.png)

The app can send emails on behalf of my google account. So, use either your testing, or the product one, not your main!


![Authentication completed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hhswp95rbc3l2l5jnem.png)

Now the authorization flow has been completed, close the authorization tab and visit back to your terminal, did the email got sent?

### It worked!

![EMAIL SENT!!](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qpr3zpxj1ecdpbzq2tk7.png)

Ok good the email is sent. Can I check my inbox?


![Email in inbox!](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u1dg44m1kb5jtyc0mjhx.png)

Seriously, I've got it in my inbox now. The email is in HTML, as the `<b>` is working as intended to bold the text and...


![Email Info](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hlukmhutkqpkzbked6op.png)

There isn't visible differences to know if this email is automated or what, but it still shows in Primary (**Person-to-person emails go in primary**).

## Wrapping up
Congrats on making a python project that can send emails! Here's what you can use this for:
- Adding email vertification for signup/login
- Making your newsletter website (flask is very easy with this)

> Just for a example, visit <cutyoururl.tech>, my URL shortener with **Python+Flask+Gmail API** that uses this same method to verify emails. GitHub: {% embed https://github.com/ashishagarwal2023/CutYourURL %}.
> Can you give it a star?