Python Email Tutorial
Sending Email with Python
Python Email Guide
Email Automation Python
Python SMTP Example

How to send an email with Python?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Python can send email through any SMTP-compatible provider, and the standard library is usually enough. The essential pieces are smtplib for transport and email.message.EmailMessage for constructing a proper message body.

Send a Basic Email with SMTP

A minimal example using SSL looks like this:

python
1import os
2import smtplib
3from email.message import EmailMessage
4
5sender = os.environ['SMTP_USER']
6password = os.environ['SMTP_PASSWORD']
7recipient = '[email protected]'
8
9message = EmailMessage()
10message['Subject'] = 'Python test email'
11message['From'] = sender
12message['To'] = recipient
13message.set_content('This message was sent from Python.')
14
15with smtplib.SMTP_SSL('smtp.example.com', 465) as smtp:
16    smtp.login(sender, password)
17    smtp.send_message(message)

This is the usual pattern for scripts, alerts, and simple automation.

Why EmailMessage Is the Right Choice

You can technically build raw email strings by hand, but that is brittle. EmailMessage handles headers, line endings, MIME formatting, and attachments correctly.

That matters as soon as the message becomes more than one plain-text line.

Add an Attachment

Attachments are straightforward with EmailMessage.

python
1import os
2import smtplib
3from email.message import EmailMessage
4
5message = EmailMessage()
6message['Subject'] = 'Report'
7message['From'] = os.environ['SMTP_USER']
8message['To'] = '[email protected]'
9message.set_content('Attached is the latest report.')
10
11with open('report.txt', 'rb') as f:
12    message.add_attachment(
13        f.read(),
14        maintype='text',
15        subtype='plain',
16        filename='report.txt',
17    )

Then send it the same way with smtp.send_message(message).

Pick the Right SMTP Settings

The code is only part of the job. You also need the provider-specific SMTP host, port, and authentication method. For example, some providers expect SSL on port 465, while others expect plain SMTP upgraded with starttls() on port 587.

So the configuration usually matters more than the Python syntax.

Keep Credentials Out of Source Code

Never hard-code passwords directly in the script. Use environment variables, secret managers, or deployment configuration.

That is especially important for automation, because the same script often ends up copied into CI, cron jobs, or shared infrastructure where credential leakage is easy.

Handle Errors Explicitly

SMTP servers can reject messages for authentication, relay, quota, or formatting reasons. Catch exceptions around the send operation so failure is visible.

python
1import smtplib
2
3try:
4    with smtplib.SMTP_SSL('smtp.example.com', 465) as smtp:
5        smtp.login(sender, password)
6        smtp.send_message(message)
7except smtplib.SMTPException as exc:
8    print(f'Email send failed: {exc}')

That is better than assuming the email was sent just because the script finished running.

HTML Email Is a Small Extension

If you need richer formatting, EmailMessage can also send HTML content with an alternative plain-text body. That is usually better than sending HTML only, because some mail clients and automated systems still prefer a plain-text representation.

Choosing the Right Provider Matters

For internal notifications, a normal SMTP mailbox may be enough. For transactional application email at scale, a dedicated provider is often a better operational choice because delivery limits, bounce handling, and reputation management become part of the problem, not just the Python code.

That distinction keeps the code example honest: sending one email with Python is easy, but operating email reliably in production is a broader delivery problem.

Common Pitfalls

  • Hard-coding SMTP credentials in the script.
  • Building raw MIME text manually instead of using EmailMessage.
  • Using the wrong SMTP host, port, or TLS mode for the provider.
  • Assuming successful script execution means the provider accepted the message.
  • Treating email sending as only a code problem when provider configuration is usually half the work.

Summary

  • Python email sending usually relies on smtplib plus EmailMessage.
  • Use provider-correct SMTP settings and authentication.
  • Keep credentials outside source code.
  • Use EmailMessage for clean message construction and attachments.
  • Catch SMTP errors so delivery failures are visible instead of silent.

Course illustration
Course illustration

All Rights Reserved.