- 代码
- 附加说明
- 要上交的内容
- 邮件客户端的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 mailserver
mailserver = #Fill in start #Fill in end
# Create socket called clientSocket and establish a TCP connection with mailserver
#Fill in start
#Fill in end
recv = clientSocket.recv(1024)
print recv
if 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 recv1
if 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 sys
import os
if 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 listening
tcpSerSock = 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 client
print('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 message
print("message.split()[1]:", message.split()[1])
filename = message.split()[1].partition("/")[2]
print("filename:", filename)
fileExist = "false"
filetouse = "/" + filename
print("filetouse:", filetouse)
try:
# Check wether the file exist in the cache
f = open("WEB/" + filetouse[1:], "rb")
outputdata = f.read()
f.close()
fileExist = "true"
# ProxyServer finds a cache hit and generates a response message
tcpCliSock.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 cache
except IOError:
if fileExist == "false":
# Create a socket on the proxyserver
c = socket(AF_INET, SOCK_STREAM)
hostn = filename.replace("www.","",1)
print("hostn:", hostn)
try:
# Connect to the socket to port 80
serverName = hostn.partition("/")[0]
serverPort = 80
print((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 client
fileobj = 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 buffer
serverResponse = 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 cache
filename = "WEB/" + filename
filesplit = 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 found
print("NET ERROR")
# Close the client and the server sockets
tcpCliSock.close()
tcpSerSock.close()
可选练习2答案
#改为Python3格式
from socket import *
import base64
import ssl
# Choose 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'
# transfer image and html
with 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_data
msg += '\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 mailserver
context = 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':
break
clientSocketSSL.close()