请教关于SMTP对象的login问题

请教关于SMTP对象的login问题



[Copy to clipboard] [ - ]
CODE:
import smtplib
s=smtplib.SMTP()
s.connect('**')
s=login('*','*')

connect 的时候没有任何问题,但是就是不能发送用户名和密码验证,错误如下:

No suitable authentication method found.


我上网搜索了一下,有这样的结果

smtplib是python自带的module,是封装了smtp,esmtp协议的模块
我试着用了一下,发现在验证用户名和密码的时候出了一些问题
下面是一些测试代码

[Copy to clipboard] [ - ]
CODE:
>>> import smtplib
>>> s = smtplib.SMTP()
>>> s.set_debuglevel(1)
>>> s.connect('smtp.263.net')
connect: ('smtp.263.net', 25)
connect: ('smtp.263.net', 25)
reply: '220 Welcome to coremail System(With Anti-Spam) 2.1 for 263(040326)\r\n'
reply: retcode (220); Msg: Welcome to coremail System(With Anti-Spam) 2.1 for 263(040326)
connect: Welcome to coremail System(With Anti-Spam) 2.1 for 263(040326)
(220, 'Welcome to coremail System(With Anti-Spam) 2.1 for 263(040326)')
>>> s.login('hust_zxq524','*****')
send: 'ehlo pc11\r\n'
reply: '250-smtp.263.net\r\n'
reply: '250-PIPELINING\r\n'
reply: '250-SIZE 30720000\r\n'
reply: '250-ETRN\r\n'
reply: '250-AUTH LOGIN\r\n'
reply: '250-AUTH=LOGIN\r\n'
reply: '250-XVERP\r\n'
reply: '250 8BITMIME\r\n'
reply: retcode (250); Msg: smtp.263.net
PIPELINING
SIZE 30720000
ETRN
AUTH LOGIN
AUTH=LOGIN
XVERP
8BITMIME
AuthMethod: None
Traceback (most recent call last):
  File "<interactive input>", line 1, in ?
  File "D:\tools\Python22\lib\smtplib.py", line 540, in login
    raise SMTPException("No suitable authentication method found.")
SMTPException: No suitable authentication method found.

然后我看了smtplib的代码,发现它支持两种认证方式,"PLAIN" 和 "CRAM-MD5",采用哪种需要根据发EHLO 命令给mailserver后,server的回复信息来确定(见blue字部分), 所以有效的回复应该是:
AUTH PLAIN CRAM-MD5
或者至少有一种。
而这里的AUTH LOGIN,我google了一下,发现某人说了这样一段话:

"本质上AUTH PLAIN和AUTH LOGIN是一样的
用户名和口令都是base64编码的明文,只不过协议命令不一样罢了

因此要说他们的区别就必须知道SASL协议了:

SASL协议里面并没有定义AUTH LOGIN,而是定义了与之相同的AUTH PLAIN
但偏偏Oultook自创AUTH LOGIN,谁让MS太NB,因此sasl的一些实现版本里面就有了AUTH LOGIN
"
然后outlook在发邮件的时候是这样做的:(在发完ehlo命令以后)
AUTH LOGIN
334 VXNlcm5hbWU6                      (Base64解码后: Username:)
Ymh3YW5n                              (Base64编码前: bhwang)
334 UGFzc3dvcmQ6                      (Base64解码后: Password:)
bXlwYXNzd29yZCFteXBhc3N3b3JkISE=      (Base64编码前: ********)
235 Authentication successful

以上验证过程中都没有加密数据,:(
我试了好几个网站,263,sina,sohu都是这样的
这样看来smtplib这个模块是没法用了,我用的是2.2,不知道2.3怎么样?


我想问,是不是通过修改smtplib里面的东西解决这样的问题呀?

可以考虑实现自己的login方法


QUOTE:
原帖由 wolfg 于 2006-9-30 17:02 发表
可以考虑实现自己的login方法

恩,我加了代码,添加了LOGIN的协议,但是还是有问题,好像 LOGIN 协议跟我刚刚引用的那个人说的不一样啊

现在报的错误改为这个了
raise SMTPAuthenticationError(code, resp)
SMTPAuthenticationError: (501, '5.5.0 Invalid input (Invalid Username; UTF-8 required).')

我没有明白为什么用户名是 UTF-8 编码的 ,这个东西是谁指定的呀? 邮件服务器?
我知道怎么回事了,我再试试

虽然上面的那个协议编码一样,但是格式上还是有很大的区别,:)
修改之后,协议算是过了,不过可能是编码上有问题,所以会报密码有错

:(
顺利解决了,呵呵:)

顺便把我修改的代码贴过了

stmplib.py 中的代码

QUOTE:
AUTH_PLAIN = "PLAIN"
        AUTH_CRAM_MD5 = "CRAM-MD5"
        AUTH_LOGIN = "LOGIN"

        if self.helo_resp is None and self.ehlo_resp is None:
            if not (200 <= self.ehlo()[0] <= 299):
                (code, resp) = self.helo()
                if not (200 <= code <= 299):
                    raise SMTPHeloError(code, resp)

        if not self.has_extn("auth"):
            raise SMTPException("SMTP AUTH extension not supported by server.")

        # Authentication methods the server supports:
        authlist = self.esmtp_features["auth"].split()

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

        # Determine the authentication method we'll use
        authmethod = None
        for method in preferred_auths:
            if method in authlist:
                authmethod = method
                break
            if '='+method in authlist:
                    authmethod = method
                    break # 本来这个部分不用加,但是我那个邮件服务器返回的是 auth=LOGIN,多了一个'=',所以我就加了这一段
        if self.debuglevel > 0:
            print "AuthMethod:", authmethod
        if authmethod == AUTH_CRAM_MD5:
            (code, resp) = self.docmd("AUTH", AUTH_CRAM_MD5)
            if code == 503:
                # 503 == 'Error: already authenticated'
                return (code, resp)
            (code, resp) = self.docmd(encode_cram_md5(resp, user, password))
        elif authmethod == AUTH_PLAIN:
            (code, resp) = self.docmd("AUTH",
                AUTH_PLAIN + " " + encode_plain(user, password))
      
# 主要就是下面这一段了         
       elif authmethod == AUTH_LOGIN:
            (code, resp) = self.docmd("AUTH", AUTH_LOGIN)
            if code == 334:
                (code, resp) = self.docmd(base64.encodestring(user)[:-1])
                if code == 334:
                    (code, resp) = self.docmd(base64.encodestring(password)[:-1])      
       elif authmethod == None:
            raise SMTPException("No suitable authentication method found.")
        if code not in [235, 503]:
            # 235 == 'Authentication successful'
            # 503 == 'Error: already authenticated'
            raise SMTPAuthenticationError(code, resp)
        return (code, resp)

if '='+method in authlist:
                    authmethod = method
                    break # 本来这个部分不用加,但是我那个邮件服务器返回的是 auth=LOGIN,多了一个'=',所以我就加了这一段

这上面的一部分是加上去的!

# 主要就是下面这一段了         
       elif authmethod == AUTH_LOGIN:
            (code, resp) = self.docmd("AUTH", AUTH_LOGIN)

这上面的一部分是修改过的(原来的内容为 (code, resp) = self.docmd("AUTH","%s %s" % (AUTH_LOGIN, encode_base64(user, eol=""))))

要是说可以成功的话。修改这两段就可以了。
学习了