免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 21478 | 回复: 8
打印 上一主题 下一主题

请教关于SMTP对象的login问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-09-30 15:02 |只看该作者 |倒序浏览

  1. import smtplib
  2. s=smtplib.SMTP()
  3. s.connect('**')
  4. s=login('*','*')
复制代码


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

No suitable authentication method found.


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

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

  1. >>> import smtplib
  2. >>> s = smtplib.SMTP()
  3. >>> s.set_debuglevel(1)
  4. >>> s.connect('smtp.263.net')
  5. connect: ('smtp.263.net', 25)
  6. connect: ('smtp.263.net', 25)
  7. reply: '220 Welcome to coremail System(With Anti-Spam) 2.1 for 263(040326)\r\n'
  8. reply: retcode (220); Msg: Welcome to coremail System(With Anti-Spam) 2.1 for 263(040326)
  9. connect: Welcome to coremail System(With Anti-Spam) 2.1 for 263(040326)
  10. (220, 'Welcome to coremail System(With Anti-Spam) 2.1 for 263(040326)')
  11. >>> s.login('hust_zxq524','*****')
  12. send: 'ehlo pc11\r\n'
  13. reply: '250-smtp.263.net\r\n'
  14. reply: '250-PIPELINING\r\n'
  15. reply: '250-SIZE 30720000\r\n'
  16. reply: '250-ETRN\r\n'
  17. reply: '250-AUTH LOGIN\r\n'
  18. reply: '250-AUTH=LOGIN\r\n'
  19. reply: '250-XVERP\r\n'
  20. reply: '250 8BITMIME\r\n'
  21. reply: retcode (250); Msg: smtp.263.net
  22. PIPELINING
  23. SIZE 30720000
  24. ETRN
  25. AUTH LOGIN
  26. AUTH=LOGIN
  27. XVERP
  28. 8BITMIME
  29. AuthMethod: None
  30. Traceback (most recent call last):
  31.   File "<interactive input>", line 1, in ?
  32.   File "D:\tools\Python22\lib\smtplib.py", line 540, in login
  33.     raise SMTPException("No suitable authentication method found.")
  34. 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里面的东西解决这样的问题呀?

[ 本帖最后由 白色乌鸦 于 2006-9-30 15:30 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2006-09-30 17:02 |只看该作者
可以考虑实现自己的login方法

论坛徽章:
0
3 [报告]
发表于 2006-09-30 17:15 |只看该作者
原帖由 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 编码的 ,这个东西是谁指定的呀? 邮件服务器?

论坛徽章:
0
4 [报告]
发表于 2006-09-30 17:22 |只看该作者
我知道怎么回事了,我再试试

虽然上面的那个协议编码一样,但是格式上还是有很大的区别,:)

论坛徽章:
0
5 [报告]
发表于 2006-09-30 17:35 |只看该作者
修改之后,协议算是过了,不过可能是编码上有问题,所以会报密码有错

:(

论坛徽章:
0
6 [报告]
发表于 2006-09-30 17:48 |只看该作者
顺利解决了,呵呵:)

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

stmplib.py 中的代码
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)

[ 本帖最后由 白色乌鸦 于 2006-9-30 18:00 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2008-01-23 10:46 |只看该作者

我成功后的经验

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=""))))

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

论坛徽章:
0
8 [报告]
发表于 2008-01-23 13:00 |只看该作者
学习了

论坛徽章:
0
9 [报告]
发表于 2008-01-23 13:14 |只看该作者
很不错。

不过建议楼主,以后有这种东西,发一个patch上来会比较好。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP