Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1c5471f

Browse files
committed
Issue #6683: For SMTP logins we now try all authentication methods advertised
by the server. Many servers are buggy and advertise authentication methods they o not support in reality. This change makes smtplib.auth() work more often in the real world, where we face misconfigured servers and servers that advertise methods they don't support due to the madness that is SASL.
1 parent ae78018 commit 1c5471f

2 files changed

Lines changed: 33 additions & 28 deletions

File tree

Lib/smtplib.py

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -559,43 +559,44 @@ def encode_plain(user, password):
559559
if not self.has_extn("auth"):
560560
raise SMTPException("SMTP AUTH extension not supported by server.")
561561

562-
# Authentication methods the server supports:
563-
authlist = self.esmtp_features["auth"].split()
562+
# Authentication methods the server claims to support
563+
advertised_authlist = self.esmtp_features["auth"].split()
564564

565565
# List of authentication methods we support: from preferred to
566566
# less preferred methods. Except for the purpose of testing the weaker
567567
# ones, we prefer stronger methods like CRAM-MD5:
568568
preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN]
569569

570-
# Determine the authentication method we'll use
571-
authmethod = None
572-
for method in preferred_auths:
573-
if method in authlist:
574-
authmethod = method
575-
break
576-
577-
if authmethod == AUTH_CRAM_MD5:
578-
(code, resp) = self.docmd("AUTH", AUTH_CRAM_MD5)
579-
if code == 503:
580-
# 503 == 'Error: already authenticated'
581-
return (code, resp)
582-
(code, resp) = self.docmd(encode_cram_md5(resp, user, password))
583-
elif authmethod == AUTH_PLAIN:
584-
(code, resp) = self.docmd("AUTH",
585-
AUTH_PLAIN + " " + encode_plain(user, password))
586-
elif authmethod == AUTH_LOGIN:
587-
(code, resp) = self.docmd("AUTH",
588-
"%s %s" % (AUTH_LOGIN, encode_base64(user.encode('ascii'), eol='')))
589-
if code != 334:
590-
raise SMTPAuthenticationError(code, resp)
591-
(code, resp) = self.docmd(encode_base64(password.encode('ascii'), eol=''))
592-
elif authmethod is None:
570+
# We try the authentication methods the server advertises, but only the
571+
# ones *we* support. And in our preferred order.
572+
authlist = [auth for auth in preferred_auths if auth in advertised_authlist]
573+
if not authlist:
593574
raise SMTPException("No suitable authentication method found.")
594-
if code not in (235, 503):
575+
576+
# Some servers advertise authentication methods they don't really
577+
# support, so if authentication fails, we continue until we've tried
578+
# all methods.
579+
for authmethod in authlist:
580+
if authmethod == AUTH_CRAM_MD5:
581+
(code, resp) = self.docmd("AUTH", AUTH_CRAM_MD5)
582+
if code == 334:
583+
(code, resp) = self.docmd(encode_cram_md5(resp, user, password))
584+
elif authmethod == AUTH_PLAIN:
585+
(code, resp) = self.docmd("AUTH",
586+
AUTH_PLAIN + " " + encode_plain(user, password))
587+
elif authmethod == AUTH_LOGIN:
588+
(code, resp) = self.docmd("AUTH",
589+
"%s %s" % (AUTH_LOGIN, encode_base64(user.encode('ascii'), eol='')))
590+
if code == 334:
591+
(code, resp) = self.docmd(encode_base64(password.encode('ascii'), eol=''))
592+
595593
# 235 == 'Authentication successful'
596594
# 503 == 'Error: already authenticated'
597-
raise SMTPAuthenticationError(code, resp)
598-
return (code, resp)
595+
if code in (235, 503):
596+
return (code, resp)
597+
598+
# We could not login sucessfully. Return result of last attempt.
599+
raise SMTPAuthenticationError(code, resp)
599600

600601
def starttls(self, keyfile = None, certfile = None):
601602
"""Puts the connection to the SMTP server into TLS mode.

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ Extensions
4040
Library
4141
-------
4242

43+
- Issue #6683: For SMTP logins we now try all authentication methods advertised
44+
by the server. Many servers are buggy and advertise authentication methods they
45+
o not support in reality.
46+
4347
- Issue #8814: function annotations (the ``__annotations__`` attribute)
4448
are now included in the set of attributes copied by default by
4549
functools.wraps and functools.update_wrapper. Patch by Terrence Cole.

0 commit comments

Comments
 (0)