Send HTML emails with Python
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Sending HTML email from Python is mostly about building the message correctly and using SMTP securely. The practical default is a multipart email with both plain-text and HTML versions, because mail clients and spam filters handle that more reliably than HTML-only messages.
Build the Message With EmailMessage
Modern Python code should usually use email.message.EmailMessage instead of manually assembling MIME parts.
That gives you a clean multipart message with a text fallback and an HTML body.
Send It Through SMTP Securely
Once the message exists, send it over SMTP with TLS.
Using an environment variable is much safer than hardcoding a password in the script.
Why the Plain-Text Part Matters
Some developers send only HTML because that is what the user sees in a rich mail client. A plain-text part is still worth including because:
- some clients display only text
- spam filters often prefer well-formed multipart messages
- accessibility tools may rely on the text version
- some environments strip HTML for security reasons
So the combination of set_content() and add_alternative() is usually the right baseline.
Keep HTML Conservative
HTML email is not the same as browser HTML. Many clients ignore advanced CSS, strip scripts, or render layout inconsistently.
A conservative example:
In email, simple inline styling is usually more reliable than external stylesheets or modern layout techniques.
Add Attachments When Needed
EmailMessage also makes attachments straightforward.
The message should still make sense without the attachment whenever possible, because some recipients or filters may block attachments.
Send to Multiple Recipients Carefully
You can send to more than one visible recipient by joining the addresses:
If you need private recipients, use blind-copy handling carefully and keep in mind that headers and SMTP envelope recipients are not identical concepts.
Test Rendering and Delivery Separately
A message can be syntactically correct and still render badly or land in spam. Testing should cover:
- MIME structure
- HTML rendering in real mail clients
- authentication success
- deliverability and spam handling
A sandbox SMTP server or mail-testing service is usually better than blasting repeated tests into a production mailbox.
Common Pitfalls
The biggest mistake is sending HTML-only email without a plain-text alternative. That reduces compatibility and can hurt deliverability.
Another common issue is hardcoding SMTP credentials in source code. Use environment variables, app passwords, or another secret-management mechanism instead.
People also copy browser-style HTML and expect it to render the same way in email clients. Email HTML support is much more limited.
Finally, do not confuse successful SMTP submission with actual inbox delivery. Deliverability also depends on reputation and mail-domain setup such as SPF, DKIM, and DMARC.
Summary
- Use
EmailMessageto build multipart email with both text and HTML content. - Send mail through SMTP with TLS and environment-based credentials.
- Keep HTML simple because email clients support less than browsers do.
- Add attachments and multiple recipients carefully, with deliverability in mind.
- Test structure, rendering, and delivery separately because successful sending is only part of the problem.

