









Python Email Tutorial
Sending Emails using SMTP
Introduction to Sending Emails with Python
Have you ever wanted your Python application to send an email—whether it’s a newsletter, a password reset link, or an alert from a monitoring system? This tutorial walks you through how to send emails using Python’s built-in smtplib
and email
libraries. No third-party packages required.
Understanding the Basics: SMTP and Email Protocols
Before diving into code, it’s helpful to know how email sending works. Email clients (like Gmail or Outlook) use SMTP (Simple Mail Transfer Protocol) to send messages. Python’s smtplib
allows you to interact with SMTP servers, and the email
library helps you structure messages in a proper format.
1. Sending a Basic Plain Text Email
Let’s start with the simplest example: sending a plain text email from a Gmail account.
import smtplib
from email.message import EmailMessage
# Setup email content
msg = EmailMessage()
msg['Subject'] = 'Test Email from Python'
msg['From'] = 'your_email@gmail.com'
msg['To'] = 'recipient@example.com'
msg.set_content('This is a test email sent from Python.')
# Gmail SMTP setup
smtp_server = 'smtp.gmail.com'
smtp_port = 587
# Send the email
with smtplib.SMTP(smtp_server, smtp_port) as server:
server.starttls() # Secure the connection
server.login('your_email@gmail.com', 'your_app_password')
server.send_message(msg)
print("Email sent successfully!")
Email sent successfully!
Explaining the Code
EmailMessage()
– a modern way to create well-formatted email messages.starttls()
– upgrades the connection to a secure encrypted one.- Use App Passwords if 2FA is enabled for Gmail. Regular passwords won’t work.
2. Sending HTML Emails
You can send beautiful, formatted HTML emails as well. Let’s modify the previous example.
msg = EmailMessage()
msg['Subject'] = 'Welcome!'
msg['From'] = 'your_email@gmail.com'
msg['To'] = 'recipient@example.com'
html_content = """
<html>
<body>
<h1>Welcome to our service!</h1>
<p>We are thrilled to have you onboard.</p>
</body>
</html>
"""
msg.set_content('This is a fallback for non-HTML clients.')
msg.add_alternative(html_content, subtype='html')
HTML content sent as an email.
3. Attaching Files to Emails
To include an attachment like a PDF or image, you can use the add_attachment()
method. Here’s how to attach a PDF file:
from pathlib import Path
pdf_path = Path('sample.pdf')
pdf_data = pdf_path.read_bytes()
msg.add_attachment(pdf_data, maintype='application', subtype='pdf', filename='sample.pdf')
Verification Tips Before Sending
- ✔️ Check that
msg['From']
and login credentials match. - ✔️ Validate recipient addresses to avoid SMTP errors.
- ✔️ If sending many emails, respect SMTP limits to avoid being blocked.
- ✔️ Use environment variables or secure config for passwords.
4. Error Handling and Common Pitfalls
It’s essential to wrap your email logic in try-except blocks to handle network errors or login failures gracefully.
try:
with smtplib.SMTP(smtp_server, smtp_port) as server:
server.starttls()
server.login('your_email@gmail.com', 'your_app_password')
server.send_message(msg)
except smtplib.SMTPAuthenticationError:
print("Login failed. Check your credentials.")
except Exception as e:
print(f"Something went wrong: {e}")
Login failed. Check your credentials.
5. How to Test Without Sending Real Emails
For testing, Python offers a local debugging SMTP server that just prints emails instead of sending:
Run this in your terminal
python -m smtpd -c DebuggingServer -n localhost:1025
with smtplib.SMTP('localhost', 1025) as server:
server.send_message(msg)
Email content will be printed in the terminal running the dummy server.
Summary – Things to Remember
- smtplib handles the email sending, while email.message handles formatting.
- Always use
starttls()
orSMTP_SSL
to keep your credentials safe. - Use try-except blocks to catch and debug common errors.
- For Gmail, generate an App Password if 2-Step Verification is enabled.
Next Steps
You can now build on this to send reports, alerts, or even newsletter campaigns using Python. Try integrating it with schedulers or form submissions for real-world automation!