classification
Title: smtplib.SMTP().sendmail() and rset()
Type: behavior Stage: resolved
Components: email Versions: Python 3.2
process
Status: closed Resolution: duplicate
Dependencies: Superseder: error responses from server are masked in smtplib when server closes connection
View: 17498
Assigned To: Nosy List: DDarko, barry, christian.heimes, jesstess, r.david.murray, zvyn
Priority: normal Keywords:

Created on 2012-09-23 12:21 by DDarko, last changed 2014-07-26 21:35 by r.david.murray. This issue is now closed.

Messages (9)
msg171029 - (view) Author: DDarko (DDarko) Date: 2012-09-23 12:21
I'm trying to send an email as follows:

smtp = smtplib.SMTP(host, port=25)
smtp.ehlo()
smtp.sendmail(from_mail, to_mail, data)

The last line / command calls the raise.
I would like to know the reason why SMTP did not accept my email?
In theory, enough to capture the exception.
However, the exception of the last line returns:
"smtplib.SMTPServerDisconnected: Connection unexpectedly closed"
This is because the smtplib get replies in:
http://hg.python.org/cpython/file/default/Lib/smtplib.py
   767         (code, resp) = self.data(msg)
Then performs:
   769             self.rset()
As a result, the SMTP server disconnects the client. And instead receive info with reason I have information about sudden disconnection.

I do not think it should be reset, and if it is wrapped in a try.

Working snippet:
(code, resp) = self.data(msg)
if code != 250:
    #self.rset()
    raise SMTPDataError(code, resp)
#if we got here then somebody got our mail
return senderrs


This happens on servers mx.google.com
msg171031 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2012-09-23 13:00
According to RFC 821 a smtp server must always apply with OK when it receives a RSET command.

RESET (RSET)

    This command specifies that the current mail transaction is
    to be aborted.  Any stored sender, recipients, and mail data
    must be discarded, and all buffers and state tables cleared.
    The receiver must send an OK reply.


It seems like your mail server violates the standards.
msg171034 - (view) Author: DDarko (DDarko) Date: 2012-09-23 13:17
The problem is that this is not my SMTP server.
I want to connect as a client with smtplib.
For this, as I said earlier it is mx.google.com



send: 'ehlo [127.0.1.1]\r\n'
reply: b'250-mx.google.com at your service, [MYIP]\r\n'
reply: b'250-SIZE 35882577\r\n'
reply: b'250-8BITMIME\r\n'
reply: b'250-STARTTLS\r\n'
reply: b'250 ENHANCEDSTATUSCODES\r\n'
reply: retcode (250); Msg: b'mx.google.com at your service, [MYIP]\nSIZE 35882577\n8BITMIME\nSTARTTLS\nENHANCEDSTATUSCODES'
send: 'mail FROM:<EMAIL> size=448\r\n'
reply: b'250 2.1.0 OK o7si11249316wiz.31\r\n'
reply: retcode (250); Msg: b'2.1.0 OK o7si11249316wiz.31'
send: 'rcpt TO:<EMAIL>\r\n'
reply: b'250 2.1.5 OK o7si11249316wiz.31\r\n'
reply: retcode (250); Msg: b'2.1.5 OK o7si11249316wiz.31'
send: 'data\r\n'
reply: b'354  Go ahead o7si11249316wiz.31\r\n'
reply: retcode (354); Msg: b'Go ahead o7si11249316wiz.31'
data: (354, b'Go ahead o7si11249316wiz.31')
send: b'Content-Type: multipart/related; boundary="===============0969887089=="\r\nMIME-Version: 1.0\r\nFrom: ....\r\n\r\n--===============0969887089==--\r\n.\r\n'
reply: b'550-5.7.1 [MYIP       7] Our system has detected that this message is\r\n'
reply: b'550-5.7.1 likely unsolicited mail. To reduce the amount of spam sent to Gmail,\r\n'
reply: b'550-5.7.1 this message has been blocked. Please visit\r\n'
reply: b'550-5.7.1 http://support.google.com/mail/bin/answer.py?hl=en&answer=188131 for\r\n'
reply: b'550 5.7.1 more information. o7si11249316wiz.31\r\n'
reply: retcode (550); Msg: b'5.7.1 [MYIP       7] Our system has detected that this message is\n5.7.1 likely unsolicited mail. To reduce the amount of spam sent to Gmail,\n5.7.1 this message has been blocked. Please visit\n5.7.1 http://support.google.com/mail/bin/answer.py?hl=en&answer=188131 for\n5.7.1 more information. o7si11249316wiz.31'
data: (550, b'5.7.1 [MYIP       7] Our system has detected that this message is\n5.7.1 likely unsolicited mail. To reduce the amount of spam sent to Gmail,\n5.7.1 this message has been blocked. Please visit\n5.7.1 http://support.google.com/mail/bin/answer.py?hl=en&answer=188131 for\n5.7.1 more information. o7si11249316wiz.31')
send: 'rset\r\n'
---
Connection unexpectedly closed
msg171060 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2012-09-23 16:48
I believe that Google is technically out of compliance with the SMTP spec here.  What they are doing is not unreasonable, since they don't have any reason to want to waste resources on talking to a server they think is spamming them.

Making this work in a more useful fashion may be considered an enhancement rather than a bug fix, since arguably it is Google, not smtplib, that appears to be violating the RFC.  On the other hand, the fix is simple enough, is unlikely to be harmful, and it can be argued that handling this error is the proper action for a robust smtp client in any case, so I think we can justify making it a bug fix.

The rset is correct in the general case, so the fix would be to wrap it in a try/except and treat SMTPServerDisconnected as not-an-error.

DDarko, would you have any interest in proposing a patch with tests?
msg171063 - (view) Author: DDarko (DDarko) Date: 2012-09-23 17:21
I do not understand why at all reset is performed ?
If moments later raise is done.

If someone despite error SMTPSenderRefused, SMTPRecipientsRefused or SMTPDataError  will still want to maintain a connection and use other data with session is likely he will call SMTP().rset() manually.

In my opinion, the most frequent use of the library are:

smtp = smtplib.SMTP(host, port=25)
smtp.ehlo()
try:
    smtp.sendmail(from_mail, to_mail, data)
except Exception as e:
    print(e)

smtp.quit()


If you wish to use session despite the error:
smtp = smtplib.SMTP(host, port=25)
smtp.ehlo()
for to_mail in mail_list:
    try:
        smtp.sendmail(from_mail, to_mail, data)
    except smtplib.SMTPRecipientsRefused as e:
        smtp.rset()
        print(e)

smtp.quit()

If we do not handle exception, reset does not matter.


IMHO patch should look like this:
http://hg.python.org/cpython/file/default/Lib/smtplib.py
745d744
<             self.rset()
756d754
<             self.rset()
760d757
<             self.rset()
msg171071 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2012-09-23 18:04
The rset just returns the connection to the "base" state, allowing a new message sending transaction to start from a known state.

In any case, since the library has done this in the past, it must continue to do this in the future, or it will break currently working code.
msg171102 - (view) Author: DDarko (DDarko) Date: 2012-09-24 06:32
I understand, in that case:

/cpython/file/default/Lib/smtplib.py
760c760,761
<             self.rset()
---
>             try: self.rset()
>             except: pass

Solves the problem.
msg171123 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2012-09-24 13:29
Well, a bare except is almost always a bad idea, and certainly is in this case.

I'll create a patch for this if no one beats me to it.
msg223795 - (view) Author: Milan Oberkirch (zvyn) * Date: 2014-07-23 23:31
This bug is fixed (at least in 3.5) so you might want to close it.
(See the _rset function in smtplib.py:482 and how its used in sendmail.)
History
Date User Action Args
2014-07-26 21:35:42r.david.murraysetstatus: open -> closed
superseder: error responses from server are masked in smtplib when server closes connection
resolution: duplicate
stage: resolved
2014-07-23 23:31:21zvynsetnosy: + zvyn, jesstess
messages: + msg223795
2012-09-24 13:29:41r.david.murraysetmessages: + msg171123
2012-09-24 06:32:43DDarkosetmessages: + msg171102
2012-09-23 18:04:14r.david.murraysetmessages: + msg171071
2012-09-23 17:21:31DDarkosetmessages: + msg171063
2012-09-23 16:48:41r.david.murraysetmessages: + msg171060
2012-09-23 13:17:28DDarkosetmessages: + msg171034
2012-09-23 13:00:56christian.heimessetnosy: + christian.heimes
messages: + msg171031
2012-09-23 12:50:25r.david.murraysetnosy: + barry, r.david.murray
components: + email, - Library (Lib)
2012-09-23 12:21:25DDarkocreate