Complete Guide to Sending HTML Emails with Python

Nov 12, 2025 · Programming · 12 views · 7.8

Keywords: Python | HTML Email | smtplib | email module | MIMEMultipart

Abstract: This article provides a comprehensive guide on sending HTML formatted emails using Python's smtplib and email modules. It covers basic HTML email sending, multi-format content support, multiple recipients handling, attachment management, image embedding, and includes complete code examples with best practices.

Fundamentals of Sending HTML Emails with Python

Python provides comprehensive email sending capabilities through its built-in smtplib and email modules. The smtplib module handles connection establishment with SMTP servers and email transmission, while the email module constructs structured email content.

Core Module Overview

The smtplib module is part of Python's standard library and supports communication with SMTP servers. Configuration requires server address, port, and authentication details.

The email.mime.multipart and email.mime.text submodules create multipart emails that can contain both plain text and HTML content simultaneously.

Basic HTML Email Implementation

Below is the fundamental code example for sending HTML emails:

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# Configure sender and recipient
sender = "my@email.com"
recipient = "your@email.com"

# Create multipart message container
msg = MIMEMultipart('alternative')
msg['Subject'] = "Test Email"
msg['From'] = sender
msg['To'] = recipient

# Create plain text version
text_content = "Hi!\nHow are you?\nHere is the link you wanted:\nhttp://www.python.org"

# Create HTML version
html_content = """<html>
  <head></head>
  <body>
    <p>Hi!<br>
       How are you?<br>
       Here is the <a href="http://www.python.org">link</a> you wanted.
    </p>
  </body>
</html>"""

# Convert content to MIME objects
text_part = MIMEText(text_content, 'plain')
html_part = MIMEText(html_content, 'html')

# Attach to message container
msg.attach(text_part)
msg.attach(html_part)

# Send email
with smtplib.SMTP('localhost') as server:
    server.sendmail(sender, recipient, msg.as_string())

Multi-format Content Support

Using MIMEMultipart('alternative') creates emails containing multiple content versions. According to RFC 2046 standards, email clients prioritize displaying the last attached part (typically HTML version), falling back to previous plain text versions if display fails.

SMTP Server Configuration

Real-world applications require actual SMTP server configuration:

# SMTP server configuration
smtp_server = "smtp.example.com"
port = 587
username = "your_username"
password = "your_password"

with smtplib.SMTP(smtp_server, port) as server:
    server.starttls()  # Enable TLS encryption
    server.login(username, password)
    server.sendmail(sender, recipient, msg.as_string())

Advanced Functionality

Multiple Recipients Support

Specify multiple recipients using comma-separated strings or lists:

recipients = ["user1@example.com", "user2@example.com", "user3@example.com"]
msg['To'] = ", ".join(recipients)

Adding CC and BCC

msg['Cc'] = "cc1@example.com, cc2@example.com"
msg['Bcc'] = "bcc1@example.com, bcc2@example.com"

Attachment Handling

Use email.mime.base.MIMEBase to add various attachment types:

from email import encoders
from email.mime.base import MIMEBase

# Add PDF attachment
filename = "document.pdf"
with open(filename, "rb") as attachment:
    part = MIMEBase("application", "octet-stream")
    part.set_payload(attachment.read())

encoders.encode_base64(part)
part.add_header("Content-Disposition", f"attachment; filename={filename}")
msg.attach(part)

Image Embedding

Embed images in HTML using CID references:

from email.mime.image import MIMEImage

# HTML content referencing CID
html_with_image = '''<html>
<body>
    <img src="cid:embedded_image">
</body>
</html>'''

# Add image attachment and set CID
with open("image.jpg", "rb") as img_file:
    img_part = MIMEImage(img_file.read())
    img_part.add_header('Content-ID', '<embedded_image>')
    msg.attach(img_part)

Best Practices

Always provide plain text fallback versions for compatibility. Reasonably control email size, recommending individual emails not exceed 10MB total. Use TLS encryption to protect authentication information. In production environments, consider using professional email sending services or APIs for better scalability and delivery rates.

Error Handling

Implement proper error handling in practical applications:

try:
    with smtplib.SMTP(smtp_server, port) as server:
        server.starttls()
        server.login(username, password)
        server.sendmail(sender, recipient, msg.as_string())
        print("Email sent successfully")
except smtplib.SMTPException as e:
    print(f"Email sending failed: {e}")

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.