目录
一、实验内容
通过完成本实验,您将更加了解SMTP协议。您还将学到使用Python实现标准协议的经验。
您的任务是开发一个简单的邮件客户端,将邮件发送给任意收件人。您的客户端将需要连接到邮件服务器,使用SMTP协议与邮件服务器进行对话,并向邮件服务器发送电子邮件。 Python提供了一个名为smtplib的模块,它内置了使用SMTP协议发送邮件的方法。但是我们不会在本实验中使用此模块,因为它隐藏了SMTP和套接字编程的细节。
为了限制垃圾邮件,一些邮件服务器不接受来源随意的TCP连接。对于下面所述的实验,您可能需要尝试连接到您的大学邮件服务器和流行的Webmail服务器(如AOL邮件服务器)。您也可以尝试从您的家和您的大学校园进行连接。
下面你会找到客户端的代码框架。您将完成代码框架。您需要填写代码的地方标有#Fill in start和#Fill in end。每个地方都可能需要不止一行代码。在某些情况下,接收邮件服务器可能会将您的电子邮件分类为垃圾邮件。当您查找从客户端发送的电子邮件时,请检查垃圾邮件文件夹。
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
二、实验过程
实验完整代码如下:
from socket import *
import base64
# 选择一个邮箱服务器,这里我们选择网易邮箱的服务器为"smtp.163.com"
mailserver = "smtp.163.com"
mailUser = '***' # 填入你邮箱的用户名
mailFromAddress = '15****468@163.com' # 填入你发送邮箱的账号
mailPassWord = 'ZUT*****AKX' # 填入你的验证码,而不是你的密码,具体原因见下
mailToAddress = '25****54@qq.com' # 填入你接受邮箱的账号
# 这段代码是用于构建一个简单的邮件消息。其中,msg包含了
# 邮件的头部信息,例如发件人、收件人和主题,以及邮件正文。
# endmsg是邮件的结尾标志。Subject代表邮件的主体,FROM为发件人,TO为收件人
msg = 'FROM: ' + mailFromAddress + '\r\n'
msg += 'TO: ' + mailToAddress + '\r\n'
msg += 'Subject: ' + 'text' + '\r\n'
msg += "\r\n I love computer net"
endmsg = "\r\n.\r\n"
# 建立与服务端的TCP连接,可以查到网易邮箱的端口号为25,qq邮箱的为465
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.')
# HELO命令通常用于与SMTP服务器建立初始连接并声明自己的身份。
# 它包含的参数通常是发送方主机的名称或IP地址。
heloCommand = 'HELO mailserver\r\n'
while True:
clientSocket.send(heloCommand.encode())
recv = clientSocket.recv(1024)
recv = recv.decode()
print(recv)
if recv[:3] == '250': # 这里表明如果接收到的服务器发送的报文前三个字符为‘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
由于现在的邮箱都有保护机制,禁止第三方脚本进行发送邮件任务,所以我们必须先对发送方邮箱进行一下设置。首先找到设置界面,找到如图所示。然后开启服务,最后邮箱会给你一个验证码用于第三方登录,所以上面填写邮箱密码的地方要填入这里给出的验证码。设置完成后,就能进行发送邮件啦。
三、实验结果
代码运行结果如下,同时你也要注意你的邮箱是否收到邮件,如果没受到,请记得检查一下垃圾邮箱。
四、附加实验
其实,如果用python发送邮件其实不必这么麻烦,只不过我们需要了解邮件发送的内部逻辑是什么。通常情况下,我们只需要使用smtplib包即可,若邮件发送成功,则会打印邮件发送成功。注:别忘了qq邮箱也同样要进行设置才能用第三方脚本发送邮件。
代码展示如下:
import smtplib
from email.mime.text import MIMEText
from email.header import Header
# 创建发送邮件的一系列相关对象
from_addr='11****13@qq.com'
password='qq******cih'
to_addr='15****468@163.com'
smtpserver='smtp.qq.com'
# 利用上面的MIMEText以及Header来帮助我们构建一个简单的邮件消息
msg=MIMEText('使用python测试发送邮件','plain','utf-8')
msg['From']=Header('119****13@qq.com')
msg['To']=Header('15****68@163.com')
subject='python SMTP 邮件测试'
msg['Subject']=Header(subject,'utf-8')
try:
# 这段代码创建了一个基于 SSL 的 SMTP 连接对象。相对于普通的 SMTP 连接,
# 基于 SSL 的 SMTP 连接会对通信内容进行加密,提高了邮件的安全性。
# SSL不支持25号端口,所以这里改成了465号端口,因此我们要用qq邮箱来发送
smtpwork=smtplib.SMTP_SSL(smtpserver)
smtpwork.connect(smtpserver,465)
smtpwork.login(from_addr,password)
smtpwork.sendmail(from_addr,to_addr,msg.as_string())
print("邮件发送成功")
except smtplib.SMTPException:
print("邮件发送失败")