Python smtplib, email and b64 libraries
We modify https://realpython.com/python-send-email/.
We need to use a local SMTP server because the smtpd
library was removed in Python 3.12.
sudo apt install mailutils
First we use plain text.
import smtplib
port = 25
smtp_server = "localhost"
sender_email = "ubuntu@localhost"
receiver_email = "ubuntu@localhost"
message = """\
Subject: The subject line
The message body.
More of the message body."""
with smtplib.SMTP(smtp_server, port) as server:
server.ehlo() # Can be omitted
server.ehlo() # Can be omitted
server.sendmail(sender_email, receiver_email, message)
Reading the email with mail
:
Return-Path: <ubuntu@localhost>
X-Original-To: ubuntu@localhost
Delivered-To: ubuntu@localhost
Received: from LAPTOP-JBell.localdomain (localhost [127.0.0.1])
by LAPTOP-JBell.localdomain (Postfix) with ESMTP id 66E72233EC
for <ubuntu@localhost>; Sun, 28 Sep 2025 00:35:55 -0400 (EDT)
Subject: The subject line
Message-Id: <[email protected]>
Date: Sun, 28 Sep 2025 00:35:55 -0400 (EDT)
From: ubuntu@localhost
X-UID: 6
Status: O
The message body.
More of the message body.
Using MIME:
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
port = 25
smtp_server = "localhost"
sender_email = "ubuntu@localhost"
receiver_email = "ubuntu@localhost"
message = MIMEMultipart("alternative")
message["Subject"] = "MIME 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)
# Send email
with smtplib.SMTP(smtp_server, port) as server:
server.sendmail(
sender_email, receiver_email, message.as_string()
)
Viewing email using Alpine (sudo apt install alpine
):
Sending an email with an attachment:
import email
import smtplib
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
port = 25
smtp_server = "localhost"
sender_email = "ubuntu@localhost"
receiver_email = "ubuntu@localhost"
subject = "An email with attachment from Python"
body = "This is an email with attachment sent from Python"
# 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()
# Send email
with smtplib.SMTP(smtp_server, port) as server:
server.sendmail(sender_email, receiver_email, text)
Viewing the email in Alpine:
And an embedded image using b64
. (See https://stackoverflow.com/questions/57829797/how-to-embed-a-base64-image-into-html-email-via-python-3-5)
import smtplib
import base64
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
port = 25
smtp_server = "localhost"
sender_email = "ubuntu@localhost"
receiver_email = "ubuntu@localhost"
data = open('image.png', 'rb').read() # read bytes from file
data_base64 = base64.b64encode(data) # encode to base64 (bytes)
data_base64 = data_base64.decode() # convert bytes to string
message = MIMEMultipart("alternative")
message["Subject"] = "Embedded image 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 = f"""\
<html>
<body>
<p>Image test.</p>
<p><img src="data:image/jpeg;base64,{data_base64}"></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)
# Send email
with smtplib.SMTP(smtp_server, port) as server:
server.sendmail(
sender_email, receiver_email, message.as_string()
)
The body of this email is the following HTML:
<html>
<body>
<p>Image test.</p>
<p><img src="data:image/jpeg;base64,iVBOR...SuQmCC"></p>
</body>
</html>
which renders as