计算机网络——自顶向下方法(第七版)Socket Programming Assignment 3:SMTP
这部分回顾Socket Programming Assignment 3: SMTP。
参考资料:
- https://github.com/jzplp/Computer-Network-A-Top-Down-Approach-Answer/blob/master/Chapter-2
- https://github.com/moranzcw/Computer-Networking-A-Top-Down-Approach-NOTES
- http://www.ruanyifeng.com/blog/2008/06/mime.html
- https://my.oschina.net/u/3314358/blog/1825595
- https://blog.csdn.net/weixin_41789943/article/details/82348946
- https://blog.csdn.net/PoetMeng/article/details/53507865
- https://zhuanlan.zhihu.com/p/146565620
- https://blog.csdn.net/chjuan1122/article/details/1046579
- https://stackoverflow.com/questions/4656287/what-rules-apply-to-mime-boundary
简介
此次作业的目的是熟悉SMTP协议,使用socket开发一个邮件客户端,主要任务如下:
- 一个基本的邮件客户端
- 带SSL命令的邮件客户端
- 实现能够收发文本和图像的客户端。
文件路径结构如下:
Socket3_SMTP/
|-- mail_client.py
|-- mail_client_ssl.py
|-- mail_client_text_pic.py
`-- picture.jpg
文件解释如下:
- mail_client.py:基本的邮件客户端;
- mail_client_ssl.py:带SSL命令的邮件客户端;
- mail_client_text_pic.py:可以传送文本以及图片的邮件客户端;
- picture.jpg:测试图片;
注意点:
- 邮件服务器不要使用163邮件服务器,建议选用qq邮件服务器,注意需要开启POP3/SMTP服务,后续输入的账号密码为开启服务后的授权码。
- 账号密码需要编码为base64,这部分可以参考如下资料:
发送邮件的步骤如下:
- 和邮件服务器建立TCP连接;
- 利用HELO命令像服务器表明身份;
- 利用auth login授权登录(输入账号密码);
- 利用MAIL FROM以及RCPT TO命令表明邮件的发送和接收方;
- 利用DATA命令发送信息;
基本的邮件客户端
只要按照之前介绍的步骤实现即可,mail_client.py代码如下:
# coding=utf-8
from socket import *
import base64
from datetime import datetime
#msg = f"\r\n I love computer networks! {datetime.today().strftime('%Y-%m-%d-%H:%M:%S')}"
msg = "\r\n I love computer networks!"
endmsg = "\r\n.\r\n"
# Choose a mail server (e.g. Google mail server) and call it mailserver
mailserver = "smtp.qq.com"
mailport = 587
# Create socket called clientSocket and establish a TCP connection with mailserver
#Fill in start
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((mailserver, mailport))
#Fill in end
# 220 <domain> Service ready
print("Start connect to smtp server!")
while True:
recv = clientSocket.recv(1024).decode()
print(recv)
if recv[:3] != '220':
print('220 reply not received from server.')
else:
print("Connect successfully!")
break
# Send HELO command and print server response.
heloCommand = 'HELO Alice\r\n'
# 250 Requested mail action okay, completed
while True:
clientSocket.send(heloCommand.encode())
recv1 = clientSocket.recv(1024).decode()
print(recv1)
if recv1[:3] != '250':
print('250 reply not received from server.')
else:
break
# 登陆
print("Start log in!")
authCommand = "auth login\r\n"
clientSocket.send(authCommand.encode())
recv2 = clientSocket.recv(1024)
print(recv2.decode())
# 邮箱
email = input("Input your email:")
emailCommand = base64.b64encode(email.encode()) + b'\r\n'
clientSocket.send(emailCommand)
recv3 = clientSocket.recv(1024)
print(recv3.decode())
# 密码
passWord = input("Input your password:")
passWordCommand = base64.b64encode(passWord.encode()) + b'\r\n'
clientSocket.send(passWordCommand)
recv4 = clientSocket.recv(1024)
print(recv4.decode())
# Send MAIL FROM command and print server response.
# Fill in start
mailCommand = f"MAIL FROM: <{email}>\r\n"
print(mailCommand)
clientSocket.send(mailCommand.encode())
recv5 = clientSocket.recv(1024)
print(recv5.decode())
# Fill in end
# Send RCPT TO command and print server response.
# Fill in start
destMail = input("Input your destMail:")
rcptCommand = f"RCPT TO: <{destMail}>\r\n"
print(rcptCommand)
clientSocket.send(rcptCommand.encode())
recv6 = clientSocket.recv(1024)
print(recv6.decode())
# Fill in end
# Send DATA command and print server response.
# Fill in start
print("Start send data!")
dataCommand = "DATA\r\n"
clientSocket.send(dataCommand.encode())
recv7 = clientSocket.recv(1024)
print(recv7.decode())
# Fill in end
# Send message data.
# Fill in start
clientSocket.send(msg.encode())
# Fill in end
# Message ends with a single period.
# Fill in start
clientSocket.send(endmsg.encode())
# Fill in end
# Send QUIT command and get server response.
# Fill in start
quitCommand = "QUIT\r\n"
clientSocket.send(quitCommand.encode())
recv8 = clientSocket.recv(1024)
print(recv8.decode())
# Fill in end
启动客户端,输入账号密码以及接收方即可在接收方邮箱收到邮件:
带SSL命令的邮件客户端
更换端口,然后调用ssl.wrap_socket函数即可,mail_client_ssl.py代码如下:
# coding=utf-8
from socket import *
import base64
import ssl
#msg = f"\r\n I love computer networks! {datetime.today().strftime('%Y-%m-%d-%H:%M:%S')}"
msg = "\r\n I love computer networks!"
endmsg = "\r\n.\r\n"
# Choose a mail server (e.g. Google mail server) and call it mailserver
mailserver = "smtp.qq.com"
mailport = 465
# Create socket called clientSocket and establish a TCP connection with mailserver
#Fill in start
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocketSSL = ssl.wrap_socket(clientSocket)
clientSocketSSL.connect((mailserver, mailport))
#Fill in end
# 220 <domain> Service ready
print("Start connect to smtp server!")
while True:
recv = clientSocketSSL.recv(1024).decode()
print(recv)
if recv[:3] != '220':
print('220 reply not received from server.')
else:
print("Connect successfully!")
break
# Send HELO command and print server response.
heloCommand = 'HELO Alice\r\n'
# 250 Requested mail action okay, completed
while True:
clientSocketSSL.send(heloCommand.encode())
recv1 = clientSocketSSL.recv(1024).decode()
print(recv1)
if recv1[:3] != '250':
print('250 reply not received from server.')
else:
break
# 登陆
print("Start log in!")
authCommand = "auth login\r\n"
clientSocketSSL.send(authCommand.encode())
recv2 = clientSocketSSL.recv(1024)
print(recv2.decode())
# 邮箱
email = input("Input your email:")
emailCommand = base64.b64encode(email.encode()) + b'\r\n'
clientSocketSSL.send(emailCommand)
recv3 = clientSocketSSL.recv(1024)
print(recv3.decode())
# 密码
passWord = input("Input your password:")
passWordCommand = base64.b64encode(passWord.encode()) + b'\r\n'
clientSocketSSL.send(passWordCommand)
recv4 = clientSocketSSL.recv(1024)
print(recv4.decode())
# Send MAIL FROM command and print server response.
# Fill in start
mailCommand = f"MAIL FROM: <{email}>\r\n"
print(mailCommand)
clientSocketSSL.send(mailCommand.encode())
recv5 = clientSocketSSL.recv(1024)
print(recv5.decode())
# Fill in end
# Send RCPT TO command and print server response.
# Fill in start
destMail = input("Input your destMail:")
rcptCommand = f"RCPT TO: <{destMail}>\r\n"
print(rcptCommand)
clientSocketSSL.send(rcptCommand.encode())
recv6 = clientSocketSSL.recv(1024)
print(recv6.decode())
# Fill in end
# Send DATA command and print server response.
# Fill in start
print("Start send data!")
dataCommand = "DATA\r\n"
clientSocketSSL.send(dataCommand.encode())
recv7 = clientSocketSSL.recv(1024)
print(recv7.decode())
# Fill in end
# Send message data.
# Fill in start
clientSocketSSL.send(msg.encode())
# Fill in end
# Message ends with a single period.
# Fill in start
clientSocketSSL.send(endmsg.encode())
# Fill in end
# Send QUIT command and get server response.
# Fill in start
quitCommand = "QUIT\r\n"
clientSocketSSL.send(quitCommand.encode())
recv8 = clientSocketSSL.recv(1024)
print(recv8.decode())
# Fill in end
启动客户端,输入账号密码以及接收方即可在接收方邮箱收到邮件:
能够收发文本和图像的客户端
实现这点的重点是增加boundary,注意实际使用boundary时要增加前缀—,介绍资料如下:
其余部分和之前类似,完整的mail_client_text_pic.py内容如下:
# coding=utf-8
from socket import *
import base64
boundary = 'b--------------------------------'
with open("picture.jpg", "rb") as f:
picdata = base64.b64encode(f.read())
# mail head
msg = f'Content-Type:multipart/related; boundary="{boundary}"\r\n\r\n'.encode()
msg += f'--{boundary}\r\n'.encode()
# text head
msg += 'Content-Type: text/html; charset=UTF-8\r\n'.encode()
msg += 'Content-Transfer-Encoding: base64\r\n\r\n'.encode()
# text, 不要包含\r\n
msg += base64.b64encode("I love computer networks!".encode())
msg += "\r\n".encode()
msg += f'--{boundary}\r\n'.encode()
# image head
msg += 'Content-Type: image/jpeg; name="picture.jpg"\r\n'.encode()
msg += 'Content-Transfer-Encoding: base64\r\n\r\n'.encode()
# image
msg += picdata + "\r\n".encode()
msg += f'--{boundary}\r\n'.encode()
endmsg = "\r\n.\r\n"
# Choose a mail server (e.g. Google mail server) and call it mailserver
mailserver = "smtp.qq.com"
mailport = 587
# Create socket called clientSocket and establish a TCP connection with mailserver
#Fill in start
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((mailserver, mailport))
#Fill in end
# 220 <domain> Service ready
print("Start connect to smtp server!")
while True:
recv = clientSocket.recv(1024).decode()
print(recv)
if recv[:3] != '220':
print('220 reply not received from server.')
else:
print("Connect successfully!")
break
# Send HELO command and print server response.
heloCommand = 'HELO Alice\r\n'
# 250 Requested mail action okay, completed
while True:
clientSocket.send(heloCommand.encode())
recv1 = clientSocket.recv(1024).decode()
print(recv1)
if recv1[:3] != '250':
print('250 reply not received from server.')
else:
break
# 登陆
print("Start log in!")
authCommand = "auth login\r\n"
clientSocket.send(authCommand.encode())
recv2 = clientSocket.recv(1024)
print(recv2.decode())
# 邮箱
email = input("Input your email:")
emailCommand = base64.b64encode(email.encode()) + b'\r\n'
clientSocket.send(emailCommand)
recv3 = clientSocket.recv(1024)
print(recv3.decode())
# 密码
passWord = input("Input your password:")
passWordCommand = base64.b64encode(passWord.encode()) + b'\r\n'
clientSocket.send(passWordCommand)
recv4 = clientSocket.recv(1024)
print(recv4.decode())
# Send MAIL FROM command and print server response.
# Fill in start
mailCommand = f"MAIL FROM: <{email}>\r\n"
print(mailCommand)
clientSocket.send(mailCommand.encode())
recv5 = clientSocket.recv(1024)
print(recv5.decode())
# Fill in end
# Send RCPT TO command and print server response.
# Fill in start
destMail = input("Input your destMail:")
rcptCommand = f"RCPT TO: <{destMail}>\r\n"
print(rcptCommand)
clientSocket.send(rcptCommand.encode())
recv6 = clientSocket.recv(1024)
print(recv6.decode())
# Fill in end
# Send DATA command and print server response.
# Fill in start
print("Start send data!")
dataCommand = "DATA\r\n"
clientSocket.send(dataCommand.encode())
recv7 = clientSocket.recv(1024)
print(recv7.decode())
# Fill in end
# Send message data.
# Fill in start
clientSocket.send(msg)
# Fill in end
# Message ends with a single period.
# Fill in start
clientSocket.send(endmsg.encode())
# Fill in end
# Send QUIT command and get server response.
# Fill in start
quitCommand = "QUIT\r\n"
clientSocket.send(quitCommand.encode())
recv8 = clientSocket.recv(1024)
print(recv8.decode())
# Fill in end
启动客户端,输入账号密码以及接收方即可在接收方邮箱收到邮件:
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Doraemonzzz!
评论
ValineLivere