Python 使用SMTP协议发送邮件

引言

问题基于《计算机网络自定向下》第二章的课后套接字编程作业:邮件客户
题目的下载链接:python 压缩包
题目如下:
这个实验结束时,您将能够更好地了解SMTP协议。您还将获得使用Python实现标准协议的经验。您的任务是开发一个简单的邮件客户端,它可以向任何收件人发送电子邮件。您的客户端将需要连接到邮件服务器,使用SMTP协议与邮件服务器进行对话,并向邮件服务器发送电子邮件消息。Python提供了一个名为smtplib的模块,该模块内置了使用SMTP协议发送邮件的方法。但是,我们不会在这个实验室中使用这个模块,因为它隐藏了SMTP和套接字编程的细节。为了限制垃圾邮件,一些邮件服务器不接受来自任意来源的TCP连接。对于下面描述的实验,您可能需要尝试同时连接到大学邮件服务器和一个流行的Webmail服务器,例如AOL邮件服务器。你也可以试着在家里和大学校园里建立联系。
附加题
您当前的SMTP邮件客户端只处理在电子邮件正文中发送的文本消息。修改您的客户端,使它可以发送包含文本和图像的电子邮件。

正文

我选择的连接的是自己QQ的邮箱服务器,mail.qq.com IP地址为58.251.106.181。为了能够进行试验,需要先登录网页QQ邮箱,在设置-账户中找到如下地方生成一个授权码。
Python 使用SMTP协议发送邮件_第1张图片
首先要知道SMTP的基本命令,参考SMTP命令行

  1. 建立与STMP服务器(58.251.106.181)的25号端口TCP连接:
from socket import *
import base64
# Choose a mail server (e.g. Google mail server) and call it mailserver
mailserver = '58.251.106.181'#smtp.qq.com
# 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).decode()
print(recv)
if recv[:3] != '220':
    print('220 reply not received from server.')

返回:220 newxmesmtplogicsvrszc13.qq.com XMail Esmtp QQ Mail Server.

  1. 先HELO,再使用qq邮箱和授权码(需要base64编码)进行登录,
# Send HELO command and print server response.
heloCommand = 'HELO Alice\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 auth login command and print server response.
heloCommand = 'auth login\r\n'
clientSocket.send(heloCommand.encode())
recv1 = clientSocket.recv(1024).decode()
print(recv1) 
print(base64.b64decode(recv1[4:]).decode())#decode("base64","strict")
# Send users command and print server response.
users = base64.b64encode(b'[email protected]') +"\r\n".encode()
print(users)
clientSocket.send(users)
recv1 = clientSocket.recv(1024).decode()
print(recv1)
# Send password and print server response.
password = base64.b64encode(b'你的授权码') +"\r\n".encode()
print(password)
clientSocket.send(password)
recv1 = clientSocket.recv(1024).decode()
print(recv1)

返回:
250-newxmesmtplogicsvrszc13.qq.com-9.46.14.43-20697823
250-SIZE 73400320
250 OK
334 VXNlcm5hbWU6(Username:)

334 UGFzc3dvcmQ6(Password:)

235 Authentication successful
显示登陆成功就可以发送信件了

  1. 然后使用mail from和rcpt to 传输发送方和接收方;我这里使用的发送方是我的QQ邮箱,接受方是网易邮箱,然后发送DATA信令就可以开始传输邮件内容了
# Send MAIL FROM command and print server response.
clientSocket.send("mail from:\r\n".encode())
recv1 = clientSocket.recv(1024).decode()
print(recv1) 
# Send RCPT TO command and print server response. 
clientSocket.send("rcpt to:\r\n".encode())
recv1 = clientSocket.recv(1024).decode()
print(recv1) 
# Send DATA command and print server response. 
clientSocket.send("DATA\r\n".encode())
print(clientSocket.recv(1024).decode())

返回:
250 OK
250 OK
354 End data with ..
最后一行告诉我们要用 ..作为邮件内容的结尾,因为服务器并不知道我们的邮件有多长,对于它来说,TCP提供一个比特流,所以需要一个邮件结尾标志

  1. 接下来就是直接发送邮件内容了,但是内容需要满足一定的格式邮件客户段才可以解析。可以参考这
headline = '''From: [email protected]\
            \r\nTo: [email protected]\
            \r\nSubject:Test for SMTP command\
            \r\n\r\n'''
msg = "This is my test!"
endmsg = "\r\n.\r\n."
# Send message data.
clientSocket.send(headline.encode())
clientSocket.send(msg.encode())
# Message ends with a single period.
clientSocket.send(endmsg.encode())
print(clientSocket.recv(1024).decode())
# Send QUIT command and get server response.
clientSocket.send("quit".encode())

然后你就可以接受到邮件了
在这里插入图片描述

Python 使用SMTP协议发送邮件_第2张图片

附加题

需要同时传输文字和图片。我们需要对图像也进行base64编码进行传输,还需要配置一下MIME的信息头
参考smtp协议 文本图片数据组合
登录代码不变,修改后半部分代码:

headline = '''From: [email protected]\
            \r\nTo: [email protected]\
            \r\nSubject:Test for SMTP command\
            \r\nMIME-Version: 1.0 \
            \r\nContent-Type: multipart/mixed; boundary="1234DED00099A";\
            \r\nContent-Transfer-Encoding: 7bit 
            \r\n\r\n'''
subTextHead = '''--1234DED00099A\r\nContent-Type: text/plain; charset=us-ascii \
            \r\nContent-Transfer-Encoding: 7bit 
            \r\n\r\n'''
subImgHead = '''--1234DED00099A\r\nContent-Type: image/jpg; name="dog.jpg";\
            \r\nContent-Transfer-Encoding: base64 \
            \r\nContent-Description: ""A photo of dog""\
            \r\n\r\n'''
subEnd = '\r\n--XX-1234DED00099A--\r\n'
msg = "This is my test!"
endmsg = "\r\n.\r\n."
# Send DATA command and print server response. 
clientSocket.send("DATA\r\n".encode())
print(clientSocket.recv(1024).decode())
# Send message data.
clientSocket.send(headline.encode())
clientSocket.send(subImgHead.encode())
with open('dog.jpg','rb') as f:
        img_data = f.read()
        base64_data = base64.b64encode(img_data)
clientSocket.send(base64_data)
clientSocket.send("\r\n".encode())
clientSocket.send(subTextHead.encode())
clientSocket.send(msg.encode())
clientSocket.send("\r\n".encode())

# Message ends with a single period.
clientSocket.send(endmsg.encode())
print(clientSocket.recv(1024).decode())
# Send QUIT command and get server response.
clientSocket.send("quit".encode())

结果NICE!:
Python 使用SMTP协议发送邮件_第3张图片

你可能感兴趣的:(python,python,tcp/ip,网络协议)