python底层socket库实现smpt邮件客户端,使用TLS/SSL加密传输,带附件发送
这个是《计算机网络:自顶向下方法》(Computer Network: A Top Down Approach)第二章的Assignment 3: Mail Client,通过自己动手实现,有助于理解SMPT协议和MIME邮件格式,实验当中的建议是不要使用python里的stmplib库,因为其隐藏了很多细节,下面的代码完成了实验当中的两个附加要求:TTL/SSL加密和发送多媒体文件。
几个关键点
- 是验证身份时使用base64编码,发送消息给邮件服务器也使用了base64
- 发送STARTTLS命令后,服务器要求加密连接后,客户端这里使用SSL模块对socket进行封装,实现加密传输数据。
- 邮件头和邮件体之间要有空行,邮件体内的段头和段文之间也要有空行。
- 分隔用boundary时前面要加两横杆(--boundary),最后消息结尾是boundary前后都要加两横杆(--boundary--)
实验可能需要用的参考资料:
qq邮箱里,通过显示邮件原文,可以查看邮件MIME格式
代码如下:
import socket
import ssl
import base64
msg = '\r\nI love computer networks!\r\n'
endmsg = '\r\n.\r\n'
# Base64
username = 'MTxxxxxxxc1OA==\r\n'
passwd = 'ZWxxxxxxmNpYQ==\r\n'
# Choose a mail server (e.g Google mail server) and call it mailserver
mailServer = ('smtp.qq.com', 587)
# Create socket called clientsocket to establish TCP connection with mailserver
clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket.connect(mailServer)
recv = clientsocket.recv(1024).decode()
print(recv)
if recv[:3] != '220':
print('220 reply not received from server.')
# Send EHLO command and print server response.
helocommand = 'EHLO gmail.com\r\n'
clientsocket.send(helocommand.encode())
recv1 = clientsocket.recv(1024).decode()
print(recv1)
if recv1[:3] != '250':
print('250 reply not received from server.')
# Send STARTTLS command
startcommand = 'STARTTLS\r\n'
clientsocket.send(startcommand.encode())
recvTemp = clientsocket.recv(1024).decode()
print(recvTemp)
# create TLS/SSL security socket
ssl_socket = ssl.wrap_socket(clientsocket)
# Send again EHLO command and print server response.
helocommand = 'EHLO gmail.com\r\n'
ssl_socket.send(helocommand.encode())
recv1 = ssl_socket.recv(1024).decode()
print(recv1)
if recv1[:3] != '250':
print('250 reply not received from server.')
# auth-login
temp = 'AUTH LOGIN\r\n'
ssl_socket.send(temp.encode())
recvTemp = ssl_socket.recv(1024).decode()
print(recvTemp)
ssl_socket.send(username.encode())
recvTemp = ssl_socket.recv(1024).decode()
print(recvTemp)
ssl_socket.send(passwd.encode())
recvTemp = ssl_socket.recv(1024).decode()
print(recvTemp)
# Send MAIL FROM command and print server response.
MailFrcommand = 'MAIL FROM: <10xxxxx58@qq.com>\r\n'
ssl_socket.send(MailFrcommand.encode())
recv2 = ssl_socket.recv(1024).decode()
print(recv2)
if recv2[:3] != '250':
print('250 reply not received from server.')
# Send RCPT TO command and print server response.
RCPTcommand = 'RCPT TO: <16xxxxxx01@qq.com>\r\n'
ssl_socket.send(RCPTcommand.encode())
recv3 = ssl_socket.recv(1024).decode()
print(recv3)
if recv3[:3] != '250':
print('250 reply not received from server.')
# Send DATA command and print server response.
DATAcommand = 'DATA\r\n'
ssl_socket.send(DATAcommand.encode())
recv4 = ssl_socket.recv(1024).decode()
print(recv4)
if recv4[:3] != '354':
print('354 reply not received from server.')
# Send header data
header = 'From: <106xxxxxx89@qq.com>\r\n'
header += 'To: <16xxxxx01@qq.com>\r\n'
header += 'Subject: Nothing\r\n'
header += 'MIME-Version: 1.0\r\n'
header += 'Content-Type: multipart/mixed;boundary=boundary123\r\n'
ssl_socket.send(header.encode())
# Send message data.
messageBody = '\r\n--boundary123\r\n'
messageBody += 'Content-Type: text/plain\r\n'
messageBody += msg
with open('output1.png', 'rb') as img:
imgData = img.read()
img64 = base64.b64encode(imgData).decode()
messageBody += '\r\n--boundary123\r\n'
messageBody += 'Content-Type: image/png\r\n'
messageBody += 'Content-Transfer-Encoding: base64\r\n'
messageBody += 'Content-Disposition: attachment; filename=output1.png\r\n'
messageBody += '\r\n' + img64 + '\r\n'
messageBody += '\r\n--boundayr123--'
ssl_socket.send(messageBody.encode())
# Message ends with a single period.
ssl_socket.send(endmsg.encode())
recv5 = ssl_socket.recv(1024).decode()
print(recv5)
if recv5[:3] != '250':
print('250 reply not received from server.')
# Send QUIT command and print server response.
qcommand = 'QUIT\r\n'
ssl_socket.send(qcommand.encode())
recv6 = ssl_socket.recv(1024).decode()
print(recv6)
if recv6[:3] != '221':
print('221 reply not received from server.')

浙公网安备 33010602011771号