- 代码
- 附加说明
- 要上交的内容
- 邮件客户端的Python代码框架
- 可选练习
- 答案
- 改为Python3格式
- Choose a mail server (e.g. Google mail server) and call it mailserver
- Create socket called clientSocket and establish a TCP connection with mailserver
- Send HELO command and print server response.
- 登录过程
- 邮箱账户经过base64编码
- 邮箱密码经过base64编码 这里不展示密码了
- Send MAIL FROM command and print server response.
- Send RCPT TO command and print server response.
- Send DATA command and print server response.
- Send message data.
- Message ends with a single period.
- Send QUIT command and get server response.
通过完成本实验,您将更加了解SMTP协议。您还将学到使用Python实现标准协议的经验。
您的任务是开发一个简单的邮件客户端,将邮件发送给任意收件人。您的客户端将需要连接到邮件服务器,使用SMTP协议与邮件服务器进行对话,并向邮件服务器发送电子邮件。 Python提供了一个名为smtplib的模块,它内置了使用SMTP协议发送邮件的方法。但是我们不会在本实验中使用此模块,因为它隐藏了SMTP和套接字编程的细节。
为了限制垃圾邮件,一些邮件服务器不接受来源随意的TCP连接。对于下面所述的实验,您可能需要尝试连接到您的大学邮件服务器和流行的Webmail服务器(如AOL邮件服务器)。您也可以尝试从您的家和您的大学校园进行连接。
代码
下面你会找到客户端的代码框架。您将完成代码框架。您需要填写代码的地方标有#Fill in start和#Fill in end。每个地方都可能需要不止一行代码。
附加说明
在某些情况下,接收邮件服务器可能会将您的电子邮件分类为垃圾邮件。当您查找从客户端发送的电子邮件时,请检查垃圾邮件文件夹。
要上交的内容
在您的上交内容中,你需要提供完整的SMTP邮件客户端的代码以及一张能显示您确实收到电子邮件的屏幕截图。
邮件客户端的Python代码框架
from socket import *msg = "\r\n I love computer networks!"endmsg = "\r\n.\r\n"# Choose a mail server (e.g. Google mail server) and call it mailservermailserver = #Fill in start #Fill in end# Create socket called clientSocket and establish a TCP connection with mailserver#Fill in start#Fill in endrecv = clientSocket.recv(1024)print recvif recv[:3] != '220':print '220 reply not received from server.'# Send HELO command and print server response.heloCommand = 'HELO Alice\r\n'clientSocket.send(heloCommand)recv1 = clientSocket.recv(1024)print recv1if recv1[:3] != '250':print '250 reply not received from server.'# Send MAIL FROM command and print server response.# Fill in start# Fill in end# Send RCPT TO command and print server response.# Fill in start# Fill in end# Send DATA command and print server response.# Fill in start# Fill in end# Send message data.# Fill in start# Fill in end# Message ends with a single period.# Fill in start# Fill in end# Send QUIT command and get server response.# Fill in start# Fill in end
可选练习
- 类似Google邮件的服务器(如地址:smtp.gmail.com,端口:587))要求您的客户端在发送MAIL FROM命令之前,需要为了身份验证和安全原因添加传输层安全(TLS)或安全套接字层(SSL)。将TLS / SSL命令添加到现有的命令中,并使用上述地址和端口为Google邮件服务器实现客户端。
- 您当前的SMTP邮件客户端只能在电子邮件正文中发送文本消息。修改您的客户端,使其可以发送包含文本和图像的电子邮件。
答案
作业3答案
```python改为Python3格式
from socket import * import base64Choose a mail server (e.g. Google mail server) and call it mailserver
mailserver = “smtp.163.com” mailUser = ‘jz163wy’ mailFromAddress = ‘jz163wy@163.com’ mailPassWord = ‘**‘ mailToAddress = ‘ecnujz@qq.com’
msg = ‘FROM: ‘ + mailFromAddress + ‘\r\n’ msg += ‘TO: ‘ + mailToAddress + ‘\r\n’ msg += ‘Subject: ‘ + ‘test’ + ‘\r\n’ msg += “\r\n I love computer networks!” endmsg = “\r\n.\r\n”
Create socket called clientSocket and establish a TCP connection with mailserver
clientSocket = socket(AF_INET, SOCK_STREAM) clientSocket.connect((mailserver, 25))
recv = clientSocket.recv(1024) recv = recv.decode() print(recv) if recv[:3] != ‘220’: print(‘220 reply not received from server.’)
Send HELO command and print server response.
heloCommand = ‘HELO mailserver\r\n’ while True: clientSocket.send(heloCommand.encode()) recv = clientSocket.recv(1024) recv = recv.decode() print(recv) if recv[:3] == ‘250’: break
登录过程
loginCommand = ‘auth login\r\n’ while True: clientSocket.send(loginCommand.encode()) recv = clientSocket.recv(1024) recv = recv.decode() print(recv) if recv[:3] == ‘334’: break
邮箱账户经过base64编码
userCommand = base64.b64encode(mailUser.encode()) + b’\r\n’ while True: clientSocket.send(userCommand) recv = clientSocket.recv(1024) recv = recv.decode() print(recv) if recv[:3] == ‘334’: break
邮箱密码经过base64编码 这里不展示密码了
passCommand = base64.b64encode(mailPassWord.encode()) + b’\r\n’ while True: clientSocket.send(passCommand) recv = clientSocket.recv(1024) recv = recv.decode() print(recv) if recv[:3] == ‘235’: break
Send MAIL FROM command and print server response.
MFCommand = ‘MAIL FROM: <’+ mailFromAddress + ‘>\r\n’ while True: clientSocket.send(MFCommand.encode()) recv = clientSocket.recv(1024) recv = recv.decode() print(recv) if recv[:3] == ‘250’: break
Send RCPT TO command and print server response.
RTCommand = ‘RCPT TO: <’+ mailToAddress + ‘>\r\n’ while True: clientSocket.send(RTCommand.encode()) recv = clientSocket.recv(1024) recv = recv.decode() print(recv) if recv[:3] == ‘250’: break
Send DATA command and print server response.
DATACommand = ‘DATA\r\n’ while True: clientSocket.send(DATACommand.encode()) recv = clientSocket.recv(1024) recv = recv.decode() print(recv) if recv[:3] == ‘354’: break
Send message data.
clientSocket.send(msg.encode())
Message ends with a single period.
while True: clientSocket.send(endmsg.encode()) recv = clientSocket.recv(1024) recv = recv.decode() print(recv) if recv[:3] == ‘250’: break
Send QUIT command and get server response.
QUITCommand = ‘QUIT\r\n’ while True: clientSocket.send(QUITCommand.encode()) recv = clientSocket.recv(1024) recv = recv.decode() print(recv) if recv[:3] == ‘221’: break
<a name="PmTCl"></a>## 可选练习1答案```python#改为Python3格式from socket import *import sysimport osif len(sys.argv) <= 1:print('Usage : "python ProxyServer.py server_ip"\n[server_ip : It is the IP Address Of Proxy Server')sys.exit(2)# Create a server socket, bind it to a port and start listeningtcpSerSock = socket(AF_INET, SOCK_STREAM)tcpSerPort = int(sys.argv[1])tcpSerSock.bind(("", tcpSerPort))print(tcpSerPort)tcpSerSock.listen(10)while 1:# Strat receiving data from the clientprint('Ready to serve...')tcpCliSock, addr = tcpSerSock.accept()print('Received a connection from:', addr)message = tcpCliSock.recv(1024)message = message.decode()print("message:", message)if(message == ''):continue# Extract the filename from the given messageprint("message.split()[1]:", message.split()[1])filename = message.split()[1].partition("/")[2]print("filename:", filename)fileExist = "false"filetouse = "/" + filenameprint("filetouse:", filetouse)try:# Check wether the file exist in the cachef = open("WEB/" + filetouse[1:], "rb")outputdata = f.read()f.close()fileExist = "true"# ProxyServer finds a cache hit and generates a response messagetcpCliSock.send("HTTP/1.1 200 OK\r\n".encode())tcpCliSock.send("Content-Type:text/html\r\n\r\n".encode())tcpCliSock.send(outputdata)print('Read from cache')# Error handling for file not found in cacheexcept IOError:if fileExist == "false":# Create a socket on the proxyserverc = socket(AF_INET, SOCK_STREAM)hostn = filename.replace("www.","",1)print("hostn:", hostn)try:# Connect to the socket to port 80serverName = hostn.partition("/")[0]serverPort = 80print((serverName, serverPort))c.connect((serverName, serverPort))askFile = ''.join(filename.partition('/')[1:])print("askFile:", askFile)# Create a temporary file on this socket and ask port 80# for the file requested by the clientfileobj = c.makefile('rwb', 0)fileobj.write("GET ".encode() + askFile.encode() + " HTTP/1.0\r\nHost: ".encode() + serverName.encode() + "\r\n\r\n".encode())# Read the response into bufferserverResponse = fileobj.read()if serverResponse.split()[0] != b'404':print('404')tcpCliSock.send("HTTP/1.1 404 Not Found\r\n\r\n".encode())tcpCliSock.close()continue# Create a new file in the cache for the requested file.# Also send the response in the buffer to client socket and the corresponding file in the cachefilename = "WEB/" + filenamefilesplit = filename.split('/')for i in range(0, len(filesplit) - 1):if not os.path.exists("/".join(filesplit[0:i+1])):os.makedirs("/".join(filesplit[0:i+1]))tmpFile = open(filename, "wb")print(serverResponse)serverResponse = serverResponse.split(b'\r\n\r\n')[1]print(serverResponse)tmpFile.write(serverResponse)tmpFile.close()tcpCliSock.send("HTTP/1.1 200 OK\r\n".encode())tcpCliSock.send("Content-Type:text/html\r\n\r\n".encode())tcpCliSock.send(serverResponse)except:print("Illegal request")c.close()else:# HTTP response message for file not foundprint("NET ERROR")# Close the client and the server socketstcpCliSock.close()tcpSerSock.close()
可选练习2答案
#改为Python3格式from socket import *import base64import ssl# Choose a mail server (e.g. Google mail server) and call it mailservermailserver = "smtp.163.com"mailUser = 'jz163wy'mailFromAddress = 'jz163wy@163.com'mailPassWord = '******'mailToAddress = 'ecnujz@qq.com'# transfer image and htmlwith open("timg.jpg","rb") as f:image_data = base64.b64encode(f.read())with open("hello.html","rb") as f:html_data = base64.b64encode(f.read())# 构造邮件正文msg = 'FROM: ' + mailFromAddress + '\r\n'msg += 'TO: ' + mailToAddress + '\r\n'msg += 'Subject: ' + 'text and picture' + '\r\n'msg += 'Content-Type:multipart/related; boundary="----=_NextPart_000_0012345JZ"\r\n'msg += 'MIME-Version: 1.0\r\n'msg += '\r\n'msg = msg.encode()msg += '------=_NextPart_000_0012345JZ\r\n'.encode()msg += 'Content-Type: text/html; charset=UTF-8\r\n'.encode()msg += 'Content-Transfer-Encoding: base64\r\n'.encode()msg += '\r\n'.encode()msg += html_datamsg += '\r\n'.encode()msg += '\r\n'.encode()msg += '------=_NextPart_000_0012345JZ\r\n'.encode()msg += 'Content-Type: image/jpeg; name="timg.jpg"\r\n'.encode()msg += 'Content-Transfer-Encoding: base64\r\n'.encode()msg += 'Content-ID: JZJZJZJZJZJZJZJZ'.encode()msg += '\r\n'.encode()msg += image_data + "\r\n".encode()msg += '\r\n'.encode()msg += '------=_NextPart_000_0012345JZ--\r\n'.encode()endmsg = "\r\n.\r\n"# Create socket called clientSocket and establish a TCP connection with mailservercontext = ssl.create_default_context()clientSocket = socket(AF_INET, SOCK_STREAM)clientSocket.connect((mailserver, 465))clientSocketSSL = context.wrap_socket(clientSocket, server_hostname=mailserver)recv = clientSocketSSL.recv(1024)recv = recv.decode()print(recv)if recv[:3] != '220':print('220 reply not received from server.')# Send HELO command and print server response.heloCommand = 'HELO mailserver\r\n'while True:clientSocketSSL.send(heloCommand.encode())recv = clientSocketSSL.recv(1024)recv = recv.decode()print(recv)if recv[:3] == '250':break# 登录过程loginCommand = 'auth login\r\n'while True:clientSocketSSL.send(loginCommand.encode())recv = clientSocketSSL.recv(1024)recv = recv.decode()print(recv)if recv[:3] == '334':break# 邮箱账户经过base64编码userCommand = base64.b64encode(mailUser.encode()) + b'\r\n'while True:clientSocketSSL.send(userCommand)recv = clientSocketSSL.recv(1024)recv = recv.decode()print(recv)if recv[:3] == '334':break# 邮箱密码经过base64编码 这里不展示密码了passCommand = base64.b64encode(mailPassWord.encode()) + b'\r\n'while True:clientSocketSSL.send(passCommand)recv = clientSocketSSL.recv(1024)recv = recv.decode()print(recv)if recv[:3] == '235':break# Send MAIL FROM command and print server response.MFCommand = 'MAIL FROM: <'+ mailFromAddress + '>\r\n'while True:clientSocketSSL.send(MFCommand.encode())recv = clientSocketSSL.recv(1024)recv = recv.decode()print(recv)if recv[:3] == '250':break# Send RCPT TO command and print server response.RTCommand = 'RCPT TO: <'+ mailToAddress + '>\r\n'while True:clientSocketSSL.send(RTCommand.encode())recv = clientSocketSSL.recv(1024)recv = recv.decode()print(recv)if recv[:3] == '250':break# Send DATA command and print server response.DATACommand = 'DATA\r\n'while True:clientSocketSSL.send(DATACommand.encode())recv = clientSocketSSL.recv(1024)recv = recv.decode()print(recv)if recv[:3] == '354':break# Send message data.clientSocketSSL.send(msg)# Message ends with a single period.while True:clientSocketSSL.send(endmsg.encode())recv = clientSocketSSL.recv(1024)recv = recv.decode()print(recv)if recv[:3] == '250':break# Send QUIT command and get server response.QUITCommand = 'QUIT\r\n'while True:clientSocketSSL.send(QUITCommand.encode())recv = clientSocketSSL.recv(1024)recv = recv.decode()print(recv)if recv[:3] == '221':breakclientSocketSSL.close()
