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() or SMTP_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!