SMTPLIB

Python smtplib cc Not Working

CC recipients missing in Python smtplib? sendmail() builds the SMTP envelope from to_addrs, not the Cc: header. Add CC/BCC to to_addrs or use send_message().

Updated Jul 1, 2026

The short answer

"Python smtplib cc Not Working" isn't an error code — it's the symptom of CC recipients never receiving an email even though a Cc: header is set. The cause: smtplib.sendmail() builds the SMTP envelope (RCPT TO) only from its to_addrs argument, ignoring message headers. Fix it by passing every recipient — To, Cc, and Bcc — in to_addrs, or use send_message(), which reads those headers for you.

What does "Python smtplib cc Not Working" mean?

This is not an SMTP reply code or a Python exception — it's a behavioral symptom. Your message arrives at the To recipients, but the addresses you put in the Cc: header never receive a copy. There's usually no traceback, because nothing technically failed: smtplib delivered exactly to the recipients you told it to.

The confusion comes from conflating two different things in email:

  • The message headers (From:, To:, Cc:) — text inside the message that mail clients display.
  • The SMTP envelope (MAIL FROM / RCPT TO) — the routing instructions the server actually uses to decide who gets the mail.

These are independent, exactly as the real envelope and letterhead of a physical letter are independent. This separation is defined in RFC 5321 §2.3.1: a mail object is transported with an envelope and content; the envelope determines delivery, and the headers are part of the content.

What causes CC to be ignored in smtplib?

SMTP.sendmail(from_addr, to_addrs, msg) builds the envelope only from its to_addrs argument. Per the Python smtplib docs:

The from_addr and to_addrs parameters are used to construct the message envelope used by the transport agents. sendmail does not modify the message headers in any way.

So if you write a Cc: header into your MIMEMultipart but pass only the To address as to_addrs, smtplib issues RCPT TO for the To recipient only. The CC header is delivered as visible text, but no RCPT TO is ever sent for those addresses — hence "CC not working." The same applies to BCC.

How do I fix CC in smtplib?

Option 1 — include every recipient in to_addrs (works on all versions). to_addrs must be the complete list of envelope recipients: To + Cc + Bcc combined.

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
to_addrs = ["alice@example.com"]
cc_addrs = ["bob@example.com", "carol@example.com"]
bcc_addrs = ["audit@example.com"]
msg = MIMEMultipart()
msg["From"] = "sender@example.com"
msg["To"] = ", ".join(to_addrs)
msg["Cc"] = ", ".join(cc_addrs) # visible header
# Do NOT add a Bcc header — keep BCC out of the message text
msg.attach(MIMEText("Hello", "plain"))
all_recipients = to_addrs + cc_addrs + bcc_addrs # the envelope
with smtplib.SMTP_SSL("smtp.example.com", 465) as s:
s.login("user", "app-password")
s.sendmail("sender@example.com", all_recipients, msg.as_string())

Note that CC recipients still get the email even though they're in to_addrsto_addrs is the envelope recipient list, not the To: header. Keep BCC addresses out of the message headers so they stay hidden, but do include them in all_recipients.

Option 2 — let send_message() read the headers for you. The higher-level SMTP.send_message() extracts recipients automatically: when to_addrs is omitted, it "combines the values (if any) of the To, Cc, and Bcc fields." It also strips the Bcc (and Resent-Bcc) header before transmission, so BCC stays private.

msg["Bcc"] = "audit@example.com" # send_message reads it, then removes it
with smtplib.SMTP_SSL("smtp.example.com", 465) as s:
s.login("user", "app-password")
s.send_message(msg) # no explicit recipient list needed

Known caveat: the Python 3.12.1 send_message() regression

There is a real CPython bug (gh-113658) where, starting in Python 3.12.1, send_message() fails to extract recipients when both a Cc and a Bcc header are present and both are set to empty strings (e.g. msg["Cc"] = "" and msg["Bcc"] = ""). In that case it sends RCPT TO:<> instead of the real recipient. Populated Cc/Bcc headers are unaffected. It was fixed in a later 3.12.x release. If you hit this, either omit the empty Cc/Bcc headers entirely, upgrade Python, or fall back to Option 1 by passing to_addrs explicitly.

Quick checklist

  • Is every CC/BCC address in to_addrs (or are you using send_message())? The header alone is never enough.
  • On Python 3.12.1 and using send_message()? Avoid setting empty Cc and Bcc headers together — that combination triggers the RCPT TO:<> bug. Upgrade or pass to_addrs explicitly.
  • For personal Gmail SMTP, authenticate with an App Password (2-Step Verification on) — Google removed "Less secure apps" access for personal accounts on May 30, 2022. For Google Workspace accounts, Less Secure Apps access was phased out later, with final removal around May 2025 — use OAuth2, or an admin-enabled App Password with 2-Step Verification, per your organization's current policy. Ports 465 (implicit TLS) and 587 (STARTTLS) both work.

FAQ

Common questions

Because smtplib.sendmail() builds the SMTP envelope (RCPT TO) only from its to_addrs argument and never reads the Cc: header. Add the CC addresses to to_addrs (to_addrs = to + cc + bcc), or switch to send_message(), which reads To/Cc/Bcc headers automatically.

One API, every provider

Stop debugging raw provider errors

Courier connects to your email, SMS, and push providers, handles retries and failover, and surfaces delivery errors in plain language.

Reply-code definitions per RFC 5321 §2.3.1. Last reviewed Jul 1, 2026. Courier is not affiliated with third-party providers; error behavior may vary by implementation.