'ValueError: There may be at most 1 To headers in a message
I am trying to write a very basic email sending script. Here is my code ..
import smtplib
from email.message import EmailMessage
msg = EmailMessage()
msg.set_content("Test message.")
msg['Subject'] = "Test Subject!!!"
msg['From'] = "[email protected]"
email_list = ["[email protected]", "[email protected]"]
for email in email_list:
msg['To'] = email
server = smtplib.SMTP(host='smtp.gmail.com', port=587)
server.starttls()
server.login("[email protected]", "mypassword")
server.send_message(msg)
server.quit()
the script should send mail to multiple recipients so, I need to change the msg['To']
field when iterating through loop But I get the following error in traceback bellow.
Traceback (most recent call last):
File "exp.py", line 66, in <module>
msg['To'] = email
File "/usr/lib/python3.8/email/message.py", line 407, in __setitem__
raise ValueError("There may be at most {} {} headers "
ValueError: There may be at most 1 To headers in a message
How do I solve ? Please help. Thank you..
Solution 1:[1]
Clean the 'To' property of the message.
for email in email_list:
msg['To'] = email
server = smtplib.SMTP(host='smtp.gmail.com', port=587)
server.starttls()
server.login("[email protected]", "mypassword")
server.send_message(msg)
server.quit()
del msg['To]
Below is the code that throws the exception: (\Python385\Lib\email\message.py)
def __setitem__(self, name, val):
"""Set the value of a header.
Note: this does not overwrite an existing header with the same field
name. Use __delitem__() first to delete any existing headers.
"""
max_count = self.policy.header_max_count(name)
if max_count:
lname = name.lower()
found = 0
for k, v in self._headers:
if k.lower() == lname:
found += 1
if found >= max_count:
raise ValueError("There may be at most {} {} headers "
"in a message".format(max_count, name))
self._headers.append(self.policy.header_store_parse(name, val))
Solution 2:[2]
Not knowing the inner working of the EmailMessage class, what I can assume is that every call to __setitem__
writes to the head of the email message, so by calling it in a loop, the header is being written multiple times, what I'd recommend is that you make an email message for every email you'll send, but create only one server:
server = smtplib.SMTP(host='smtp.gmail.com', port=587)
server.starttls()
server.login("[email protected]", "mypassword")
email_list = ["[email protected]", "[email protected]"]
for email in email_list:
msg = EmailMessage()
msg.set_content("Test message.")
msg['Subject'] = "Test Subject!!!"
msg['From'] = "[email protected]"
msg['To'] = email
server.send_message(msg)
server.quit()
Only if you need for the messages to be sent separately. If you want to send the same message to everyone at the same time you could do something like
msg['To'] = ', '.join(email_list)
Solution 3:[3]
If you have a list of addresses, and some of them include a name/title, then I think this is the correct way to do it. Please note that parseaddr + formataddr pair may not be needed, but parseaddr can correct some malformed recipients.
from email.header import Charset
from email.message import EmailMessage, MIMEPart
from email.utils import formataddr, parseaddr
test_recipients = [
"Mr. John Doe <[email protected]>",
"Mr. Jane Doe <[email protected]>",
"[email protected]"
]
to_header= []
for raw_address in (test_recipients):
# Parse and recreate
title, email = parseaddr(raw_address)
if title and email:
to_header.append(f"{title} <{email}>")
elif email:
to_header.append(email)
# Encode after join
message.add_header("To", Charset("utf-8").header_encode(", ".join(to_header)))
Solution 4:[4]
if you just delete server.quit() from loop and add del msg['to'] then there is no error
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | balderman |
Solution 2 | fixmycode |
Solution 3 | nagylzs |
Solution 4 | mohit sinha |