问题
I am wondering why this code
test = smtplib.SMTP('smtp.gmail.com', 587)
test.ehlo()
test.starttls()
test.ehlo()
test.login('address','passw')
test.sendmail(sender, recipients, composed)
test.close()
works, but when written like this
with smtplib.SMTP('smtp.gmail.com', 587) as s:
s.ehlo()
s.starttls()
s.ehlo()
s.login('address','passw')
s.sendmail(sender, recipients, composed)
s.close()
it fails with the message
Unable to send the email. Error: <class 'AttributeError'>
Traceback (most recent call last):
File "py_script.py", line 100, in <module>
with smtplib.SMTP('smtp.gmail.com', 587) as s:
AttributeError: __exit__
Why is this happening? (python3 on a raspberry pi) Thx
回答1:
You are not using Python 3.3 or up. In your version of Python, smtplib.SMTP()
is not a context manager and cannot be using in a with
statement.
The traceback is directly caused because there is no __exit__ method, a requirement for context managers.
From the smptlib.SMTP() documentation:
Changed in version 3.3: Support for the
with
statement was added.
You can wrap the object in a context manager with @contextlib.contextmanager:
from contextlib import contextmanager
from smtplib import SMTPResponseException, SMTPServerDisconnected
@contextmanager
def quitting_smtp_cm(smtp):
try:
yield smtp
finally:
try:
code, message = smtp.docmd("QUIT")
if code != 221:
raise SMTPResponseException(code, message)
except SMTPServerDisconnected:
pass
finally:
smtp.close()
This uses the same exit behaviour as was added in Python 3.3. Use it like this:
with quitting_smtp_cm(smtplib.SMTP('smtp.gmail.com', 587)) as s:
s.ehlo()
s.starttls()
s.ehlo()
s.login('address','passw')
s.sendmail(sender, recipients, composed)
Note that it'll close the connection for you.
来源:https://stackoverflow.com/questions/27882100/python-sending-a-mail-fails-when-inside-a-with-block