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:
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.
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.
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
smtplibplusEmailMessage. - Use provider-correct SMTP settings and authentication.
- Keep credentials outside source code.
- Use
EmailMessagefor clean message construction and attachments. - Catch SMTP errors so delivery failures are visible instead of silent.

