You may have found this tutorial because you want to send email using Python. Maybe you want to write a code to receive email reminders, send a confirmation email to users when they create an account, or send an email to organization members to remind them to pay their dues. Sending mail is a time-consuming and error prone task, but it can be easily automated using Python.
Note here: whether you are for Python employment or hobbies, remember: project development experience is always the core. If you don't have the latest Python introduction to the advanced practical video tutorial in 2020, you can go to the small Python exchange : you can find a lot of new Python tutorial projects under the transformation of "seven clothes, nine seven buses and five numbers" (homophony of numbers). You can also communicate with the old driver for advice!
In this tutorial, you will learn how to:
-
Use SMTP_SSL() and. starttls() to set up a secure connection
-
Send basic e-mail using Python's built-in smtplib Library
-
Use email package to send email with HTML content and attachments
-
Send multiple personalized e-mails of CSV files containing contact data
-
Just a few lines of code to send e-mail through a Gmail account using the Yagmail package
You will find some transactional email services at the end of this tutorial that will be useful when you want to send a large number of emails.
Ready to start
Python built in smtplib Module to send e-mail using the simple mail transfer protocol (SMTP). SMTP lib used in SMTP RFC 821 agreement. The example in this tutorial uses a Gmail SMTP server to send e-mail, but the same principles apply to other e-mail services. Although most email providers use the same connection port as in this tutorial, you can use Google search to quickly confirm.
To start this tutorial, first set up a Gmail account for development, or set up an SMTP debugging server. Instead of sending, the mail will be printed to the console. These two options are listed below. The local SMTP debugging server can be used to fix any problems with the e-mail feature and ensure that your e-mail feature is error free before sending any e-mail.
Option 1: set up a Gmail account for development
If you decide to send email using a Gmail account, I strongly recommend that you set up a one-time account for your development code. This is because you have to adjust the security settings of your Gmail account to allow access from your Python code, and you may accidentally disclose your login details. In addition, I found that the inbox of my test account soon filled with test email, which is enough for you to set up a new Gmail account for development.
A good feature of Gmail is that you can use the + sign to add any modifier to the email address before the @ sign. For example, emails sent to my + personal1@gmail.com and my + personal2@gmail.com will be sent to my@gmail.com. When testing the email function, you can use this function to simulate all multiple addresses pointing to the same inbox.
To create a Gmail address for your test code:
- Create a new Google account
- take Allow insecure app settings Enabled for. Please note that this makes it easier for others to access your account.
If you don't want to lower the security settings for your Gmail account, check Google's File , learn how to use Python scripts for OAuth2 authorization to obtain access credentials.
Option 2: set up a local SMTP server
You can use Python's pre installed smptd module to run a local SMTP debugging server to test email functionality. Instead of sending emails to the specified address, it discards them and prints their contents to the console. Running a local debugging server means that you do not need to process message encryption or log in to the e-mail server with credentials.
You can start the local SMTP debugging server by entering the following at the command prompt:
python -m smtpd -c DebuggingServer -n localhost:1025 Copy code
On Linux, add sudo before the same command.
Any email sent through this server will be discarded and a bytes object will be displayed on each line in the terminal window:
---------- MESSAGE FOLLOWS ----------
b'X-Peer: ::1'
b''
b'From: my@address.com'
b'To: your@address.com'
b'Subject: a local test mail'
b''
b'Hello there, here is a test email'
------------ END MESSAGE ------------
Copy code
For the rest of this tutorial, I assume you're using a Gmail account, but if you're using a local debugging server, make sure you use localhost as the SMTP server address and port 1025 instead of port 465 or 587. In addition, you don't need to use login() or SSL / TLS to encrypt communication.
Send a plain text message
Before we dive into sending emails with HTML content and attachments, you'll learn to send plain text emails using Python. These are emails you can write in a simple text editor. There is no such oddity as text formatting or hyperlinks. You'll find out later.
Start a secure SMTP connection
When you send email through Python, make sure your SMTP connection is encrypted so that other people can't easily access your mail and login credentials. SSL (secure socket layer) and TLS (Transport Layer Security) are two protocols that can be used to encrypt SMTP connections. When using a local debugging server, you do not need to use any of them.
There are two ways to establish a secure connection to your email server:
- Use SMTP? Ssl() to establish a secure SMTP connection
- Use an insecure SMTP connection, then use. starttls() encryption
In both cases, Gmail encrypts e-mail using TLS because this is a more secure version of SSL. According to Python's Safety precautions , it is strongly recommended that you use ssl Create? Default? Context () in the module. This will load the system's trusted CA certificate, enable host name checking and certificate validation, and try to choose the appropriate secure protocol and password settings.
If you want to check your Gmail inbox for encrypted e-mail messages, go to more → show original content to see the encryption types listed under the received heading.
smtplib Is a built-in module for Python that uses the SMTP or ESMTP listener daemons to send e-mail to any Internet computer.
I'll show you how to use smtp_ssl () first, because it instantiates a secure connection from the beginning and is slightly simpler than using the. Starttls () alternative. Note that if you use SMTP_SSL(), Gmail requires you to connect to port 465, and if you use. starttls(), you need to connect to port 589.
Option 1: use SMPT? Ssl()
The following code example initializes a TLS encrypted connection using SMTP_SSL() of smtplib to establish a secure connection with the SMTP server of Gmail. SSL's default context validates the host name and its certificate and optimizes the security of the connection. Be sure to fill in your own email address instead of my@gmail.com:
import smtplib, ssl
port = 465 # For SSL
password = input("Type your password and press enter: ")
# Create a secure SSL context
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", port, context=context) as server:
server.login("my@gmail.com", password)
# TODO: Send email here
Copy code
Use with smtplib.SMTP_SSL() as server to ensure that the connection is automatically closed at the end of the indented code block. If port is zero or not specified,. SMTP_SSL() uses the standard port (Port 465).
Storing your email password in code is not secure, especially if you plan to share it with others. Instead, use input() to let the user enter the password when running the script, as shown in the example above. If you do not want the password to appear on the screen when you enter it, you can import getpass Module and use. getpass() instead of entering the password directly.
Option 2: use. starttls()
We can create an insecure SMTP connection and encrypt it with. starttls(), instead of using. SMTP_SSL() to create a secure connection from the beginning.
To do this, create an instance of smtplib.SMTP that encapsulates the SMTP connection and allows you to access its methods. I recommend that you define the SMTP server and port at the beginning of the script to easily configure them.
The following snippet uses server= SMTP() instead of with SMTP() as server: the format we used in the previous example. To ensure that the code does not crash in the event of a problem, place the main code in the try block and have the except ion block print any error messages to stdout:
import smtplib, ssl
smtp_server = "smtp.gmail.com"
port = 587 # For starttls
sender_email = "my@gmail.com"
password = input("Type your password and press enter: ")
# Create a secure SSL context
context = ssl.create_default_context()
# Try to log in to server and send email
try:
server = smtplib.SMTP(smtp_server,port)
server.ehlo() # Can be omitted
server.starttls(context=context) # Secure the connection
server.ehlo() # Can be omitted
server.login(sender_email, password)
# TODO: Send email here
except Exception as e:
# Print any error messages to stdout
print(e)
finally:
server.quit()
Copy code
To notify the server that it knows itself, it should call.Helo () (SMTP) or.Ehlo () (ESMTP) after creating the.SMTP() object and then call it after.Starttls (). This function is implicitly called by. starttls() and. sendmail(), so unless you want to check the server's SMTP service extension, you don't have to explicitly call. helo() or. ehlo().
Send your plain text message
After initiating a secure SMTP connection using any of the above methods, you can use. sendmail() to send email:
server.sendmail(sender_mail, receiver_email, message) Copy code
I recommend defining email addresses and message content at the top of the script after import so you can easily change them:
sender_email = "my@gmail.com"
receiver_email = "your@gmail.com"
message = """\
Subject: Hi there
This message is sent from Python."""
# Send email here
Copy code
The message string begins with "Subject: Hi there" followed by two line breaks (\ n). This ensures that Hi there is displayed for the Subject of the email and that the text following a new line is treated as the body of the email.
The following code example uses SMTP? Ssl() to send plain text e-mail:
import smtplib, ssl
port = 465 # For SSL
smtp_server = "smtp.gmail.com"
sender_email = "my@gmail.com" # Enter your address
receiver_email = "your@gmail.com" # Enter receiver address
password = input("Type your password and press enter: ")
message = """\
Subject: Hi there
This message is sent from Python."""
context = ssl.create_default_context()
with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, message)
Copy code
This is a code example of sending plain text e-mail by encrypting the SMTP connection with. starttls(). By contrast, the server.ehlo() line can be omitted because if necessary, they are implicitly called by. starttls() and. sendmail():
import smtplib, ssl
port = 587 # For starttls
smtp_server = "smtp.gmail.com"
sender_email = "my@gmail.com"
receiver_email = "your@gmail.com"
password = input("Type your password and press enter:")
message = """\
Subject: Hi there
This message is sent from Python."""
context = ssl.create_default_context()
with smtplib.SMTP(smtp_server, port) as server:
server.ehlo() # Can be omitted
server.starttls(context=context)
server.ehlo() # Can be omitted
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, message)
Copy code
Send fancy email
Python's built-in email package allows you to build more fancy emails, which can then be transferred using smptlib. Next, you'll learn how to use the email package to send emails with HTML content and attachments.
Contains HTML content
Html is handy if you want to format the text in your email (bold, italics, etc.), or if you want to add any images, hyperlinks, or responsive content. Today's most common e-mail type is MIME (Multipurpose Internet Mail Extension) multipart e-mail, which combines HTML and plain text. MIME messages are processed by Python's email.mime module. For detailed instructions, see File .
Because not all e-mail clients display HTML content by default, and for security reasons, some people only choose to receive plain text e-mail, so it is important to add a plain text alternative to HTML messages. Since the email client will first render the last part of the attachment, make sure to add the HTML message after the plain text version.
In the following example, our MIMEText() object will contain the HTML and plain text versions of the message, and the mimemiultipart ("alternative") instance will combine these into a message with two alternate rendering options:
import smtplib, ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
sender_email = "my@gmail.com"
receiver_email = "your@gmail.com"
password = input("Type your password and press enter:")
message = MIMEMultipart("alternative")
message["Subject"] = "multipart test"
message["From"] = sender_email
message["To"] = receiver_email
# Create the plain-text and HTML version of your message
text = """\
Hi,
How are you?
Real Python has many great tutorials:
www.realpython.com"""
html = """\
<html>
<body>
<p>Hi,<br>
How are you?<br>
<a href="http://www.realpython.com">Real Python</a>
has many great tutorials.
</p>
</body>
</html>
"""
# Turn these into plain/html MIMEText objects
part1 = MIMEText(text, "plain")
part2 = MIMEText(html, "html")
# Add HTML/plain-text parts to MIMEMultipart message
# The email client will try to render the last part first
message.attach(part1)
message.attach(part2)
# Create secure connection with server and send email
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
server.login(sender_email, password)
server.sendmail(
sender_email, receiver_email, message.as_string()
)
Copy code
In this example, you first define plain text and HTML messages as string text, and then store them as plain / HTML mime text objects. These can then be added to the mime multipart ("alternative") messages in order and sent over a secure connection to the e-mail server. Remember to add HTML messages after the replacement plain text, because the e-mail client will try to render the last subpart first.
Use email to add attachments
In order to send binaries to an e-mail server designed to process text data, they need to be encoded before transmission. This is usually done using base64, which encodes binary data into printable ASCII characters.
The following code example shows how to attach a PDF file when sending an email:
import email, smtplib, ssl
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
subject = "An email with attachment from Python"
body = "This is an email with attachment sent from Python"
sender_email = "my@gmail.com"
receiver_email = "your@gmail.com"
password = input("Type your password and press enter:")
# Create a multipart message and set headers
message = MIMEMultipart()
message["From"] = sender_email
message["To"] = receiver_email
message["Subject"] = subject
message["Bcc"] = receiver_email # Recommended for mass emails
# Add body to email
message.attach(MIMEText(body, "plain"))
filename = "document.pdf" # In same directory as script
# Open PDF file in binary mode
with open(filename, "rb") as attachment:
# Add file as application/octet-stream
# Email client can usually download this automatically as attachment
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
# Encode file in ASCII characters to send by email
encoders.encode_base64(part)
# Add header as key/value pair to attachment part
part.add_header(
"Content-Disposition",
f"attachment; filename= {filename}",
)
# Add attachment to message and convert message to string
message.attach(part)
text = message.as_string()
# Log in to server using secure context and send email
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, text)
Copy code
MIMEultipart() accept RFC5233 Parameters in the form of key / value pairs of the style, which are stored in the dictionary and passed to the. Add ﹣ header method of the Message base class.
Check the documentation for Python's email.mime module for more information about using MIME classes.
Send multiple personalized emails
Imagine that you want to email members of your organization to remind them to pay for their contributions. Or, you may want to send a personalized email to students in your class that includes the results of recent assignments. These tasks are easy in Python.
Making CSV file with relevant personal information
The simple start to sending multiple personalized e-mails is to create a CSV (comma separated values) file that contains all the required personal information. (make sure that other people's private information is not shared without their consent.) A CSV file can be treated as a simple table, where the first row usually contains column headings.
Here is the contents of the contacts file.csv file, which I saved in the same folder as the Python code. It contains the names, addresses, and grades of a group of fictional characters. I use the my+modifier@gmail.com construct to ensure that all email ends up in my own inbox, in this case my@gmail.com:
name,email,grade
Ron Obvious,my+ovious@gmail.com,B+
Killer Rabbit of Caerbannog,my+rabbit@gmail.com,A
Brian Cohen,my+brian@gmail.com,C
Copy code
When creating a CSV file, make sure to separate your values with commas, without any spaces.
Traverse rows to send multiple messages
The following code example shows how to open a CSV file and loop its content line (skipping the title line). To make sure the code works before you send email to all contacts. I've printed Sending email to... For each contact, and we can replace them later with the function of actually sending email:
import csv
with open("contacts_file.csv") as file:
reader = csv.reader(file)
next(reader) # Skip header row
for name, email, grade in reader:
print(f"Sending email to {name}")
# Send email here
Copy code
In the example above, use open(filename) as file: to make sure your file is closed at the end of the code block. csv.reader() can read the CSV file line by line and extract its value. next(reader) skips the title line, followed by the line for name, email, grade in reader: use the unpacking operation in Python, and store the result value in the name, email and score of the current contact.
If the values in the CSV file contain spaces on either or both sides, you can delete them using the. strip() method.
Personalized content
You can use str.format() to fill in the brace placeholder and put personalized content into the message. For example, "hi {name}, you {result} your assignment".format(name="John", result="passed") will give you "hi John, you passed your assignment".
Starting with Python 3.6, you can do string formatting more elegantly with f-string, but these require you to define placeholders before the f-string itself. To define e-mail messages at the beginning of the script and fill in placeholders for each contact as you loop through the CSV file, use the older. format() method.
With this in mind, you can set up a generic message body that can be customized placeholders for individuals.
Code case
The following code example allows you to send personalized email to multiple contacts. It will loop through the CSV file to show each contact's name, email, score, as shown in the example above.
The general message is defined at the beginning of the script. For each contact in the CSV file, the {name} and {grade} placeholders are filled in, and personalized email is sent through a secure connection with the Gmail server, as you have seen before:
import csv, smtplib, ssl
message = """Subject: Your grade
Hi {name}, your grade is {grade}"""
from_address = "my@gmail.com"
password = input("Type your password and press enter: ")
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
server.login(from_address, password)
with open("contacts_file.csv") as file:
reader = csv.reader(file)
next(reader) # Skip header row
for name, email, grade in reader:
server.sendmail(
from_address,
email,
message.format(name=name,grade=grade),
)
Copy code
Yagmail
There are multiple libraries that make it easier for you to send e-mail, such as Envelopes,Flanker And Yagmail . Yagmail is designed for Gmail, which greatly simplifies the process of sending e-mail through a friendly API, as shown in the following code example:
import yagmail
receiver = "your@gmail.com"
body = "Hello there from Yagmail"
filename = "document.pdf"
yag = yagmail.SMTP("my@gmail.com")
yag.send(
to=receiver,
subject="Yagmail test with attachment",
contents=body,
attachments=filename,
)
Copy code
This code example sends email with PDF attachment, which greatly reduces the amount of code we use to send email using email and smtplib.
When you set up Yagmail, you can add Gmail authentication to the operating system's keyring, such as File As described in. If you don't, Yagmail will prompt you to enter a password and automatically store it in the Keyring if you need to.
Transactional mail service
If you plan to send a large number of emails, want to view email statistics, and want to ensure reliable delivery, you may need to view transactional email services. While all of the services below send a large number of paid packages for email, they also offer free packages so you can try them out. Some of these free programs are available indefinitely and may be enough to meet your email needs.
Here is an overview of the free program for some of the major transactional email services. Clicking the provider name will go to the pricing section of its website.
supplier | Free package |
---|---|
Sendgrid | 40000 free in the first 30 days, next 100 / day |
Sendinblue | 200 / day |
Mailgun | 10000 free at the beginning |
Mailjet | 200 / day |
Amazon SES | 62000 / month |
You can run Google search to see the provider that best suits your needs, or just try some free programs to see which API you like best.
Sendgrid code example
This is a code example of sending e-mail using Sendgrid, which provides you with a way to use Python's transactional e-mail service:
import os
import sendgrid
from sendgrid.helpers.mail import Content, Email, Mail
sg = sendgrid.SendGridAPIClient(
apikey=os.environ.get("SENDGRID_API_KEY")
)
from_email = Email("my@gmail.com")
to_email = Email("your@gmail.com")
subject = "A test email from Sendgrid"
content = Content(
"text/plain", "Here's a test email sent through Python"
)
mail = Mail(from_email, subject, to_email, content)
response = sg.client.mail.send.post(request_body=mail.get())
# The statements below can be included for debugging purposes
print(response.status_code)
print(response.body)
print(response.headers)
Copy code
To run this code, you must first:
- Sign up for a (free) Sendgrid account
- Request an API key For user authentication
- Add the API key by typing setx sendgroup ﹣ API ﹣ key "you ﹣ API ﹣ key" at the command prompt, or set sendgroup ﹣ API ﹣ key you ﹣ API ﹣ key to store it only for the current client session
Finally note: whether you are for Python employment or hobbies, remember: project development experience is always the core. If you don't have the latest Python introduction to the advanced practical video tutorial in 2020, you can go to the small Python exchange : you can find a lot of new Python tutorial projects under the transformation of "seven clothes, nine seven buses and five numbers" (homophony of numbers). You can also communicate with the old driver for advice!
The text and pictures of this article come from the Internet and my own ideas. They are only for learning and communication. They have no commercial use. The copyright belongs to the original author. If you have any questions, please contact us in time for handling.
summary
You can now start a secure SMTP connection and send multiple personalized emails to people in your contact list!
You've learned how to use plain text as an alternative to sending HTML e-mail and attaching files to your e-mail. When you use a Gmail account, the Yagmail package simplifies all of these tasks. If you plan to send a lot of emails, it's worth studying transactional email services.
Enjoy sending email in Python, but remember: please don't spam!