python
smtplib
email
multiple recipients
tutorial

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.

python
1import smtplib
2from email.message import EmailMessage
3
4sender = "[email protected]"
5recipients = ["[email protected]", "[email protected]"]
6
7message = EmailMessage()
8message["Subject"] = "Status update"
9message["From"] = sender
10message["To"] = ", ".join(recipients)
11message.set_content("Hello everyone, this is the report.")
12
13with smtplib.SMTP("smtp.example.com", 587) as server:
14    server.starttls()
15    server.login("[email protected]", "password")
16    server.send_message(message, from_addr=sender, to_addrs=recipients)

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:

python
message["To"] = "[email protected], [email protected]"

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.

python
1import smtplib
2from email.message import EmailMessage
3
4sender = "[email protected]"
5recipients = ["[email protected]", "[email protected]", "[email protected]"]
6
7msg = EmailMessage()
8msg["Subject"] = "Reminder"
9msg["From"] = sender
10msg["To"] = ", ".join(recipients)
11msg.set_content("Meeting starts at 10:00.")
12
13with smtplib.SMTP("smtp.example.com", 587) as smtp:
14    smtp.starttls()
15    smtp.login("[email protected]", "password")
16    smtp.sendmail(sender, recipients, msg.as_string())

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.

python
cc = ["[email protected]"]
bcc = ["[email protected]"]
all_recipients = recipients + cc + bcc

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.
  • 'EmailMessage is the clean modern way to construct the email.'
  • 'To, Cc, and Bcc visibility 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.

Course illustration
Course illustration

All Rights Reserved.