classification
Title: smtplib msg['To] = appends instead of assigning
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 2.7
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: Xavier Bonaventura, r.david.murray
Priority: normal Keywords:

Created on 2018-05-24 10:50 by Xavier Bonaventura, last changed 2018-05-24 17:07 by r.david.murray. This issue is now closed.

Messages (3)
msg317550 - (view) Author: Xavier Bonaventura (Xavier Bonaventura) Date: 2018-05-24 10:50
The behavior when you assign an email to 'To' is counter intuitive.
When you do:

msg['To'] = 'foo@mail.com'

this appends the email instead of really assigning it.
This is because the assignment operator is overwritten.

Imagine that you have code like this:

msg = MIMEText("The report at *link* has been updated")
for recipient in recipient_list:
    msg['To'] = recipient_email
    server.sendmail(from_address, recipient_email, msg.as_string())

This will send the email to the first person N times, to the second N-1, etc.

In case that you want to debug, it is also a problem. In case that the append is the expected behaviour, one would expect that at least if you do a print like this you see the full list.

print(msg['To'])

Instead of that, in this example of code:
msg['To'] = 'foo@mail.com'
msg['To'] = 'foo@mail.com'
print(msg['To'])

It will print:
foo@mail.com

But the message will be sent two times.
msg317570 - (view) Author: Xavier Bonaventura (Xavier Bonaventura) Date: 2018-05-24 13:40
I've seen that in the documentation is quite clear with it. The question would be if the print should behave different, it is quite difficult to debug if not.

__setitem__(name, val)
Add a header to the message with field name name and value val. The field is appended to the end of the message’s existing fields.

Note that this does not overwrite or delete any existing header with the same name. If you want to ensure that the new header is the only one present in the message with field name name, delete the field first, e.g.:

del msg['subject']
msg['subject'] = 'Python roolz!'
msg317588 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2018-05-24 17:07
smtplib doesn't define any behavior for messages.  I presume you are talking about the email library?

Vis the print behavior, dict-style lookup is defined to return the first matching header.  If you want to see all of them, you can use get_all.  For debugging, you should print the whole message, which would show the duplicate headers:

>>> from email.message import Message
>>> msg = Message()
>>> msg['To'] = 'abc@xyz.com'
>>> msg['To'] = 'xyz@abc.com'
>>> print(msg)
To: abc@xyz.com
To: xyz@abc.com



With the new API this is better, at least in terms of debugging:

>>> from email.message import EmailMessage
>>> msg = EmailMessage()
>>> msg['To'] = 'abc@xyz.com'
>>> print(msg)
To: abc@xyz.com


>>> msg['To'] = 'xyz@abc.com'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/rdmurray/python/p38/Lib/email/message.py", line 408, in __setitem__
    "in a message".format(max_count, name))
ValueError: There may be at most 1 To headers in a message


This can't be changed in the old API for backward compatibility reasons.
History
Date User Action Args
2018-05-24 17:07:26r.david.murraysetstatus: open -> closed

nosy: + r.david.murray
messages: + msg317588

resolution: out of date
stage: resolved
2018-05-24 13:40:02Xavier Bonaventurasetmessages: + msg317570
2018-05-24 10:50:33Xavier Bonaventuracreate