Of course! Setting up an email host in Python means using a library to send emails. The most common and standard library for this is smtplib, which is built into Python.

Here’s a comprehensive guide covering:
- The Core Concept: How Python sends email.
- A Simple Example: Sending a plain text email.
- A Complete Example: Sending an HTML email with an attachment.
- Crucial Security Best Practices.
- Popular Third-Party Services: (Gmail, Outlook, SendGrid).
The Core Concept: smtplib and email
Python uses two main libraries to handle email:
smtplib: This library handles the transport. It connects to an SMTP (Simple Mail Transfer Protocol) server, authenticates, and sends the email data.email: This library helps you construct the email message itself. It handles headers (likeTo:,Subject:,From:), content (plain text, HTML), and attachments.
Think of it like mailing a physical letter:
smtplibis the post office and the mail carrier.emailis you writing the letter, putting it in an envelope, and adding a return address.
A Simple Example: Sending a Plain Text Email
This is the most basic case. We'll use a public SMTP server for testing, like smtp.mailtrap.io, which is great for development.

Prerequisites: You need to sign up for a free account on a service like Mailtrap to get a username, password, and server details.
import smtplib
from email.message import EmailMessage
# --- Configuration ---
# Replace with your email provider's details
SMTP_SERVER = "smtp.mailtrap.io"
SMTP_PORT = 2525
SMTP_USERNAME = "your_mailtrap_username" # e.g., "a1b2c3d4e5f6g7"
SMTP_PASSWORD = "your_mailtrap_password" # e.g., "h8i9j0k1l2m3n4"
# --- Email Content ---
sender_email = "your_sender_email@example.com"
receiver_email = "receiver_email@example.com"
subject = "Test Email from Python"
body = "Hello, this is a test email sent using Python and smtplib!"
# --- Create the Email Message ---
msg = EmailMessage()
msg.set_content(body) # Set the plain text body
msg['Subject'] = subject
msg['From'] = sender_email
msg['To'] = receiver_email
# --- Send the Email ---
try:
# Create a secure SSL context (more on this later)
# For Mailtrap, we use starttls()
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
# Start the TLS encryption
server.starttls()
# Login to your email account
server.login(SMTP_USERNAME, SMTP_PASSWORD)
# Send the email
server.send_message(msg)
print("Email sent successfully!")
except Exception as e:
print(f"Failed to send email: {e}")
A Complete Example: HTML Email with an Attachment
This example is more realistic. It sends a nicely formatted HTML email and attaches a file.
import smtplib
import os.path
from email.message import EmailMessage
# --- Configuration ---
# Replace with your email provider's details
SMTP_SERVER = "smtp.mailtrap.io"
SMTP_PORT = 2525
SMTP_USERNAME = "your_mailtrap_username"
SMTP_PASSWORD = "your_mailtrap_password"
# --- Email Content ---
sender_email = "your_sender_email@example.com"
receiver_email = "receiver_email@example.com"
subject = "Python Email with Attachment"
# --- Create the Email Message ---
msg = EmailMessage()
# 1. Set the HTML body
html_body = """
<html>
<body>
<h1>This is an HTML Email!</h1>
<p>This email was sent using Python's <b>email</b> and <b>smtplib</b> libraries.</p>
<p>It includes an attachment of a simple text file.</p>
</body>
</html>
"""
msg.set_content(html_body, 'html') # Set the content as HTML
# 2. Add a subject
msg['Subject'] = subject
# 3. Add sender and receiver
msg['From'] = sender_email
msg['To'] = receiver_email
# --- Add an Attachment ---
# Let's create a dummy file to attach
attachment_filename = "my_document.txt"
attachment_path = os.path.join(os.getcwd(), attachment_filename)
# Create the dummy file if it doesn't exist
if not os.path.exists(attachment_path):
with open(attachment_path, "w") as f:
f.write("This is the content of the attached file.")
# Read the file and add it to the email
try:
with open(attachment_path, 'rb') as f:
file_data = f.read()
# Add the file as an application/octet-stream
# EmailMessage will guess the filename from the path
msg.add_attachment(file_data, maintype='application', subtype='octet-stream', filename=attachment_filename)
except Exception as e:
print(f"Could not attach file: {e}")
# --- Send the Email ---
try:
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
server.starttls()
server.login(SMTP_USERNAME, SMTP_PASSWORD)
server.send_message(msg)
print("Email with attachment sent successfully!")
# Clean up the dummy file
os.remove(attachment_path)
except Exception as e:
print(f"Failed to send email: {e}")
Crucial Security Best Practices
You should NEVER hardcode your email credentials directly into your script. Use environment variables.
Why? If you commit your code to a public repository (like GitHub), your password will be exposed for anyone to see.

How to do it:
-
Set Environment Variables:
- macOS/Linux: In your terminal, run:
export EMAIL_HOST_USER="your_username" export EMAIL_HOST_PASSWORD="your_password"
- Windows (Command Prompt):
set EMAIL_HOST_USER="your_username" set EMAIL_HOST_PASSWORD="your_password"
- Windows (PowerShell):
$env:EMAIL_HOST_USER="your_username" $env:EMAIL_HOST_PASSWORD="your_password"
- macOS/Linux: In your terminal, run:
-
Modify your Python script to read them:
import os import smtplib from email.message import EmailMessage # Read credentials from environment variables SMTP_USERNAME = os.environ.get('EMAIL_HOST_USER') SMTP_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD') # Check if credentials are set if not SMTP_USERNAME or not SMTP_PASSWORD: raise ValueError("EMAIL_HOST_USER and EMAIL_HOST_PASSWORD environment variables not set!") # ... rest of your script
Popular Third-Party Email Services
Most major email providers require SSL/TLS encryption. This is why you see server.starttls() in the examples. It upgrades the connection to be secure.
Gmail
Gmail is very popular but has a major caveat: Less Secure Apps. For most use cases, you should use an App Password instead of your main Google password.
- Enable 2-Step Verification on your Google Account.
- Generate an App Password: Go to your Google Account > Security > App Passwords. Generate a new password for "Mail" on your "Computer (custom name)".
- Use the generated 16-character password as
SMTP_PASSWORD.
Gmail SMTP Settings:
- Server:
smtp.gmail.com - Port:
587(forstarttls) - Port:
465(for SSL, requiressmtplib.SMTP_SSL)
# Gmail Example
import smtplib
import os
SMTP_SERVER = "smtp.gmail.com"
SMTP_PORT = 587
SMTP_USERNAME = os.environ.get('GMAIL_USER') # Your Gmail address
SMTP_PASSWORD = os.environ.get('GMAIL_APP_PASSWORD') # Your 16-char App Password
# ... rest of the code from the examples above ...
Outlook / Office 365
Outlook's SMTP server settings are well-documented.
Outlook SMTP Settings:
- Server:
smtp.office365.com - Port:
587 - Encryption:
STARTTLS
# Outlook Example
import smtplib
import os
SMTP_SERVER = "smtp.office365.com"
SMTP_PORT = 587
SMTP_USERNAME = os.environ.get('OUTLOOK_USER') # Your Outlook email
SMTP_PASSWORD = os.environ.get('OUTLOOK_PASSWORD') # Your Outlook password
# ... rest of the code from the examples above ...
SendGrid (Transactional Email Service)
For applications that send a lot of transactional emails (password resets, receipts), a service like SendGrid is a better choice than a personal email account.
- Sign up for a free SendGrid account and get an API Key.
- You don't use
smtplibdirectly in the same way. You make an API request.
Using the sendgrid library:
pip install sendgrid
import os
import sendgrid
from sendgrid.helpers.mail import Mail, Email, To, Content
# --- Configuration ---
SENDGRID_API_KEY = os.environ.get('SENDGRID_API_KEY')
SENDER_EMAIL = "your_sendgrid_verified_sender@example.com"
RECEIVER_EMAIL = "receiver_email@example.com"
if not SENDGRID_API_KEY:
raise ValueError("SENDGRID_API_KEY environment variable not set!")
# --- Create the Email Message ---
message = Mail(
from_email=Email(SENDER_EMAIL),
to_emails=To(RECEIVER_EMAIL),
subject='Sending with SendGrid is Fun',
plain_text_content='and easy to do anywhere, even with Python!')
# --- Send the Email via API ---
try:
sg = sendgrid.SendGridAPIClient(api_key=SENDGRID_API_KEY)
response = sg.send(message)
print(f"Email sent! Status code: {response.status_code}")
except Exception as e:
print(f"Failed to send email: {e}") 