How to send email to multiple recipients using python smtplib?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Sending to multiple recipients with Python smtplib is mostly about separating message headers from the actual recipient list used by SMTP. The To header controls how the email looks to humans, while the recipient list passed to the SMTP send call controls where the server actually delivers it.
Use EmailMessage and a Recipient List
Modern Python code should usually build the email with email.message.EmailMessage.
The important detail is that to_addrs=recipients is a real Python list. That is what the SMTP client uses for delivery.
Why the To Header Alone Is Not Enough
A common misconception is that adding several addresses to message["To"] automatically controls delivery. It does not. SMTP delivery uses the envelope recipients passed to the send call.
For example, this header is just display text:
If you forget to pass the matching recipient list to send_message or sendmail, the server may not deliver to everyone you expect.
Using sendmail Directly
If you prefer the lower-level API, sendmail works too.
Again, the second argument to sendmail is the actual list of recipients.
That separation becomes especially important in scripts that build custom recipient lists dynamically from databases, CSV files, or notification rules.
Add Cc and Bcc Carefully
If you want Cc, include those addresses both in the header and in the SMTP recipient list.
Bcc is different. You usually do not set a visible Bcc header for all recipients to see. Instead, include the Bcc addresses only in the delivery list.
Then set message["Cc"] if desired, but do not expose Bcc in a normal visible header.
Handle Authentication and Provider Rules
Real SMTP providers often require:
- TLS or SSL
- authenticated login
- app passwords or API-specific credentials
- rate-limit compliance
So the code structure can be correct while delivery still fails because of provider policy rather than Python syntax. Logging SMTP responses during development can save a lot of time when the bug is authentication, throttling, or sender-policy enforcement rather than recipient handling.
Common Pitfalls
A common mistake is passing a comma-separated string where the SMTP call expects a list of recipient addresses. Another is assuming the To header alone controls delivery. Developers also often forget that Cc and Bcc recipients must be included in the SMTP envelope list if they should actually receive the message. Finally, hardcoding passwords in source code is a security problem; use environment variables or secret-management tooling instead.
Summary
- Build the message headers for display, but pass a real recipient list to the SMTP send call.
- '
EmailMessageis the clean modern way to construct the email.' - '
To,Cc, andBccvisibility are different from SMTP envelope delivery.' - Use TLS and authenticated login when your provider requires it.
- Treat credentials and recipient handling carefully, because message formatting and actual delivery are separate concerns.

