Send Emails in Python with Gmail

Send emails in a few lines of code

Peter Xie
Towards Data Science

--

This post will explain how to set up an app password in Google account and use Python to send emails in a few lines of code for automatic reporting, test automation or CI/CD failure notification etc.

Google Account Setup

To use a Gmail account to send emails with a third party app, e.g. Python script, in this case, we need to set up an app password. For security reasons, the normal Gmail password is restricted to web login only. And as of 2020 even you turn on the ‘Less Secure App Access’ option in your google account, which is mentioned in some other posts, you won’t be able to log in to your Gmail account with the normal password in a Python script.

First, you need to enable 2-Step Verification. Just go to your Google Account > Security > Signing in to Google, and select 2-Step Verification and follow the instruction.

Enable 2-Step Verification

Next, create an app password. Just select ‘App passwords’ under ‘2-Step Verification’ and you will see a window as follows. Select ‘Other’ in the ‘Select app’ dropdown.

App password / Step 1

And enter a name, e.g. Python, and click ‘GENERATE’. Note this name has no link to the Python script and it could be anything.

App password / Step 2

Then you will get a new app password. Copy and save the 16-character password without space, e.g. xnwbjmgvjeeevlgc, to use in your Python script.

App password / Step 3

Send Emails with yagmail

yagmail is a wrapper of Python standard library smtplib, which makes sending emails a breeze.

To install yagmail in Python, simply run pip install yagmail.

Below is a sample script sending an email with two attachments.

The code is so simple and self-explained, so it barely needs any explanation. Apart from your Gmail username and app password, you just define to, subject and content just like writing an email from web Gmail. The content is a list, and the first element is the body text part and the rest are attachments. In this example, we attach ‘pytest.ini’ and ‘test.png’ from the same folder where the script resides.

To run this script, simply run python send_gmail_by_yagmail.py in any platform, Windows, Linux or MacOS. And you will get an email in the recipient account as follows.

Sample Email

To send a group of recipients, simply change ‘to’ to a list.

to = [‘user1@gmail.com’, ‘user2@yahoo.com’]

Note that yagmail uses gmail SMTP server by default, and you can explicitly define the SMTP server and port.

host = 'smtp.gmail.com'
port = 465
with yagmail.SMTP(user, password, host, port) as yag:

And you can send HTML content as well, just add it to the contents as follows.

html_content = '<a href="https://pypi.org/">pypi</a>'
contents = ['mail body content', html_content, 'pytest.ini','test.png']

Use Python Standard Library

We can also use Python standard library without installing any additional packages to send emails.

First, we import the standard email and smtplib packages, and define related variables.

  • Gmail username and app password
  • Gmail host and port
  • To
  • Subject
  • Body content
  • Attachment
Standard lib / Part 1

Second, we define an email message object with the information above. The message is defined as a MIMEMultipart so that we can add attachments, and each part is a MIMEText object, which supports binary files as well.

Standard lib / Part 2

Note: If you want to send HTML content instead of text, just change ‘plain’ to ‘html’ as follows.

content_html = '<html><body><h1>This is a Title</h1></body></html>'
message.attach(MIMEText(content_html, 'html', 'utf-8'))

Lastly, we call smtplib to login and send the message.

Standard lib / Part 3

You can find the full script send_gmail_standard_lib.py here. And of course to run, just type python send_gmail_standard_lib.py.

Changes in Python 3.6+

The two examples above support Python 3.5 or even lower. A new EmailMessage API was introduced in Python 3.6 to define the email. You can refer to the latest document and an example here for more detail.

FAQ

You can encounter UnicodeDecodeError on non-English Windows OS as follows.

server = smtplib.SMTP_SSL(smtp_host, smtp_port)
File "C:\Program Files (x86)\Python37-32\lib\smtplib.py", line 1031, in __init__
source_address)
File "C:\Program Files (x86)\Python37-32\lib\smtplib.py", line 261, in __init__
fqdn = socket.getfqdn()
File "C:\Program Files (x86)\Python37-32\lib\socket.py", line 676, in getfqdn
hostname, aliases, ipaddrs = gethostbyaddr(name)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc3 in position 2: invalid continuation byte

This seems a bug in Python smtplib module. The reason is that your computer name contains non-English characters. So the workaround is simply to rename your computer name with English only characters.

References

https://github.com/kootenpv/yagmail
https://mp.weixin.qq.com/s/AMYeOiMX7URc_PFczqQ-5Q
https://docs.python.org/3/library/smtplib.html
https://docs.python.org/3/library/email.html

--

--