DecayFang  

问题来自于《自顶向下》套接字编程的第三题:https://github.com/moranzcw/Computer-Networking-A-Top-Down-Approach-NOTES/blob/master/SocketProgrammingAssignment/%E4%BD%9C%E4%B8%9A3-%E9%82%AE%E4%BB%B6%E5%AE%A2%E6%88%B7%E7%AB%AF/%E4%BD%9C%E4%B8%9A3-%E9%82%AE%E4%BB%B6%E5%AE%A2%E6%88%B7%E7%AB%AF-%E7%BF%BB%E8%AF%91.md

上手就是第一个坑。该书第二章以及该题的代码模板中皆没有提及授权登录的问题,实际上目前国内的email提供商(腾讯、163等)对于第三方登录都采取授权登录的方式(gmail因为一些众所周知的原因没试过),如果直接按照书中方式发送邮件会出现如下错误。

实际上我们可以将书上示例的smtp握手过程扩充成如下所示。

S: 220 xxx.com
C: HELO yourname
S: 250 greeting contents
C: AUTH LOGIN
S: 334 dXNlcm5hbWU6    #username
C: <your_username_in_base64>
S: 334 UGFzc3dvcmQ6    #password
C: <your_password_in_base64>
S: 235 AUTH successful
C: MAIL FROM: <from_mail_address>
S: 250 OK
C: RCPT TO: <to_mail_address>
S: 250 OK
C: DATA
S: 354 End data with <CR><LF>.<CR><LF>
C: main body of the message
             ...
             ...
C: .
S: 250 Mail accepted
C: QUIT
S: Bye

其中‘your_username_in_base64’和'your_password_in_base64'分别是你的邮箱用户名和授权码的base64编码,授权码可以从邮箱提供商获得,具体方法请百度。

看到这里,如果你和我一样迫不及待地去telnet一下smtp.163.com,尝试用上述的命令手工发送一封邮件的话,那你就会踩进第二个坑里。

好吧这个问题我花了两天,直到现在也没找出原因,实际上我后来尝试自己抓了一份outlook发送邮件的完整过程的包。

可以看到与我贴出的smtp握手过程基本一致,并且同样是输入我的邮箱地址的base64编码,得到的却是334肯定的回答,最终成功将邮件发出。初步猜测是windows键盘输入的问题。

这题最终的代码如下,这个smtp客户端能够正常工作,而不会像手动telnet那样报错。

 1 from socket import *
 2 msg = "\r\n I love computer networks!"
 3 endmsg = "\r\n.\r\n"
 4 # Choose a mail server (e.g. Google mail server) and call it mailserver 
 5 mailserver = 'smtp.163.com'
 6 serverPort = 25
 7 # Create socket called clientSocket and establish a TCP connection with mailserver
 8 fromaddress = 'decayfang@163.com'
 9 toaddress = '1186565149@qq.com'
10 
11 username = "ZGVjYXlmYW5nQDE2My5jb20="
12 password = "xxxxxxxxxxxxxxxxxxxxxxxx"
13 
14 clientSocket = socket(AF_INET, SOCK_STREAM)
15 clientSocket.connect((mailserver, serverPort))
16 
17 recv = clientSocket.recv(1024).decode()
18 print(recv)
19 if recv[:3] != '220':
20     print('220 reply not received from server.')
21 
22 # Send HELO command and print server response.
23 heloCommand = 'HELO Alice\r\n'
24 clientSocket.send(heloCommand.encode())
25 recv1 = clientSocket.recv(1024).decode()
26 print(recv1)
27 if recv1[:3] != '250':
28     print('250 reply not received from server.')
29     
30 authCommand = 'AUTH LOGIN\r\n'
31 clientSocket.send(authCommand.encode())
32 recv = clientSocket.recv(1024).decode()
33 print(recv)
34 if recv[:3] != '334':
35     print('334 reply not received from server.')
36     
37 clientSocket.send((username + '\r\n').encode())
38 recv = clientSocket.recv(1024).decode()
39 print(recv)
40 if recv[:3] != '334':
41     print('334 reply not received from server.')
42     
43 clientSocket.send((password + '\r\n').encode())
44 recv = clientSocket.recv(1024).decode()
45 print(recv)
46 if recv[:3] != '235':
47     print('235 reply not received from server.')
48 
49 # Send MAIL FROM command and print server response.
50 # Fill in start
51 clientSocket.send(('MAIL FROM: <' + fromaddress + '>\r\n').encode())
52 recv = clientSocket.recv(1024).decode()
53 print(recv)
54 if recv[:3] != '250':
55     print('250 reply not received from server.')
56 # Fill in end
57 
58 # Send RCPT TO command and print server response.
59 # Fill in start
60 clientSocket.send(('RCPT TO: <' + toaddress + '>\r\n').encode())
61 recv = clientSocket.recv(1024).decode()
62 print(recv)
63 if recv[:3] != '250':
64     print('250 reply not received from server.')
65 # Fill in end
66 
67 # Send DATA command and print server response.
68 # Fill in start
69 clientSocket.send('DATA\r\n'.encode())
70 recv = clientSocket.recv(1024).decode()
71 print(recv)
72 if recv[:3] != '354':
73     print('354 reply not received from server.')
74 # Fill in end
75 
76 # Send message data.
77 # Fill in start
78 message = 'From: ' + fromaddress + '\r\n'
79 message += 'To: ' + toaddress + '\r\n'
80 message += 'Subject: TESTING MAIL\r\n'
81 message += msg + '\r\n'
82 clientSocket.send(message.encode())
83 # Fill in end 
84 
85 # Message ends with a single period.
86 # Fill in start
87 clientSocket.send(endmsg.encode())
88 recv = clientSocket.recv(1024).decode()
89 print(recv)
90 if recv[:3] != '250':
91     print('250 reply not received from server.')
92 # Fill in end
93 
94 # Send QUIT command and get server response.
95 # Fill in start
96 clientSocket.send('QUIT'.encode())
97 # Fill in end
98 
99 input('Press <Enter>')

 

posted on 2020-03-29 15:31  DecayFang  阅读(583)  评论(0)    收藏  举报