Community

Sending Emails Using Python: A Practical Guide

By 4 min read 1,258 views
Featured image for Sending Emails Using Python: A Practical Guide

Sending Emails Using Python

Sending emails using Python is a routine task in automation, alerting, and application integration. Python ships with a standard library that covers both simple text messages and rich HTML emails with attachments, all without third-party dependencies. The core tools are smtplib for the SMTP protocol and email.mime for building properly formatted messages. This guide walks through the mechanics, provider choices, and practical patterns you need to send reliably.

More from this site

Keep reading the latest coverage

Browse latest →

Core Libraries for Sending Emails

The smtplib module implements an SMTP client session object that can connect to any standard mail server. It handles the handshake, authentication, and data transfer, but it does not help you format the message body or headers. That is the job of the email.mime submodules, which let you build multipart messages with plain-text and HTML alternatives, inline images, and file attachments. Together, these two modules cover everything from a one-line notification to a structured campaign email.

SMTP Providers and Connection Details

Before you write code, you need an SMTP endpoint and credentials. Many services expose a standard SMTP interface, which keeps the Python code identical while letting you swap providers behind the scenes. The differences are the host, port, and whether TLS or SSL is required.

ProviderSMTP HostPort (TLS)Port (SSL)Notes
Gmailsmtp.gmail.com587465Requires App Password if 2FA is on
Outlook / Microsoft 365smtp.office365.com587Use STARTTLS on 587
Yahoosmtp.mail.yahoo.com587465App Password required for most accounts
SendGridsmtp.sendgrid.net587465API key works as the username
AWS SESemail-smtp.region.amazonaws.com587465Uses IAM SMTP credentials

Sending a Plain-Text Email

The simplest use case is a plain-text message sent over a TLS connection. You create an SMTP object, call starttls() for port 587 connections, log in with your credentials, and pass the message string to sendmail(). The email.message.EmailMessage class from the standard library handles header formatting automatically, which is safer than hand-crafting strings.

Typical steps:

  • Import smtplib and email.message.
  • Create an EmailMessage and set Subject, From, and To.
  • Set the body with set_content().
  • Connect to the SMTP server, start TLS if needed, and log in.
  • Call server.send_message(message) and close the connection.

Sending HTML Emails

HTML messages let you include formatting, links, and inline images. You build an EmailMessage, set the Content-Type header to text/html, and pass the HTML string as the body. For multipart messages that include both plain text and HTML, use make_alternative() so clients that strip HTML still show readable text.

Adding Attachments

The email.mime module provides classes for every common MIME type. For file attachments, read the file in binary mode, guess the MIME type, and use MIMEBase with encoders.encode_base64(). Then attach it to the message with add_attachment(). The same pattern works for images, PDFs, CSVs, and any binary blob you need to ship alongside the email body.

Error Handling and Common Failures

Network issues, bad credentials, or recipient rejections all raise exceptions from smtplib. The most common ones are SMTPAuthenticationError, SMTPConnectError, and smtplib.SMTPRecipientsRefused. Wrapping your send logic in a try/except block and logging the specific exception gives you a clear signal when something goes wrong. For production systems, implement a retry with backoff for transient network failures, and validate addresses before sending to reduce bounces.

Security Best Practices

Never hardcode credentials in your source code. Use environment variables, a secrets manager, or a configuration file that is excluded from version control. When using Gmail, an App Password is required if the account has two-factor authentication enabled; the account password itself will not work. For TLS, always prefer starttls() on port 587 or an explicit SSL connection on port 465, and verify the server certificate where possible.

Alternatives to Direct SMTP

If managing SMTP credentials and deliverability feels like a burden, transaction email services such as SendGrid, Mailgun, and Amazon SES offer Python SDKs that wrap the SMTP layer and add analytics, templates, and bounce handling. The trade-off is a dependency on a third-party service and, in most cases, a cost per email or monthly volume tier. For internal tooling and low-volume alerts, the standard library remains the fastest path to a working solution.

Editor's pick

Keep exploring our latest stories

Fresh reads, picked daily.

Browse latest
Share: