背景知识
- 了解 SMTP协议详解以及工作过程
重点了解“SMTP的连接和发送过程”和“SMTP常用的命令” - copy官方给的python代码框架
1)梳理逻辑(摘自SMTP的连接和发送过程):
(a)建立TCP连接(使用Socket)
(b)客户端发送HELO/EHLO命令以标识发件人自己的身份, 接受 服务器端响应;
(c)客户端发送AUTH LOGIN登录请求,接着发送用户名和密码;
(d)客户端发送RCPT命令,以标识该电子邮件的计划接收人,可以有多个RCPT行;
(e)协商结束,发送邮件,用命令DATA发送
(f)以.表示结束输入内容一起发送出去
(g)结束此次发送,用QUIT命令退出
2)每个命令都以\r\n
结尾,特定格式命令:
HELO
:HELO <domain> <CRLF>
RCPT TO
:<forward-path> <CRLF>——<forward-path>
3)选择邮箱服务器
gmail还要翻墙,弃用(¬ 。¬)
我是使用网易邮箱作为邮箱服务器,公司邮箱作为目标账户。
网易邮箱需要提前进行一些设置,开启STMP功能,方法如下:
- 登录邮箱 -- 设置 -- 进入POP3/SMTP/IMAP界面,可以看最下面提示有SMTP服务器:
smtp.163.com
- 勾选 IMAP/SMTP服务,会弹出提示设置授权码
- 进入设置授权码,开启服务,这里需要手机号码验证(如果你和我一样,关联的手机号码已经不知道丢哪里了,可以换一个绑定当前手机的网易邮箱,(^ ^)),总之,设置好授权码后,这个授权码就是代码里的
password
下面是最终代码展示:
from socket import *
import base64
msg = 'I love computer networks!'
endmsg = '\r\n.\r\n'
# 邮件服务器,端口 25
mailserver = 'smtp.163.com'
fromaddr = 'z****@163.com' # 填写自己的邮箱
toaddr = 'z***@***.com' # 填写目标邮箱
username = 'z****@163.com'
password = 'a*****6' # 网易邮箱授权码
# 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.')
# 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
base64_str = ('\x00' + username + '\x00' + password).encode()
base64_str = base64.b64encode(base64_str)
authCommand = 'AUTH PLAIN '.encode() + base64_str + '\r\n'.encode()
clientSocket.send(authCommand)
recv_auth = clientSocket.recv(1024)
print(recv_auth.decode())
# Send MAIL FROM command and print server response.
mailCommand = 'MAIL FROM: <' + fromaddr + '>\r\n'
clientSocket.send(mailCommand.encode())
recv_from = clientSocket.recv(1024).decode()
print(recv_from)
if recv_from[:3] != '250':
print('250 reply not received from server.')
# Send RCPT TO command and print server response.
rcptCommand = 'RCPT TO: <' + toaddr + '>\r\n'
clientSocket.send(rcptCommand.encode())
recv_rcpt = clientSocket.recv(1024).decode()
print(recv_rcpt)
if recv_rcpt[:3] != '250':
print('250 reply not received from server.')
# Send DATA command and print server response.
clientSocket.send('DATA\r\n'.encode())
recv_data = clientSocket.recv(1024).decode()
print(recv_data)
if (recv_data[:3] != '354'):
print('354 reply not received from server')
# Send message data.
send_msg = 'from: ' + fromaddr + '\r\n'
send_msg += 'to: ' + toaddr + '\r\n'
send_msg += 'subject: ' + msg + '\r\n'
send_msg += 'content-type: text/plain\t\n'
send_msg += '\r\n' + msg
clientSocket.send(send_msg.encode())
# Message ends with a single period.
clientSocket.send(endmsg.encode())
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '250'):
print('250 reply not received from server')
# Send QUIT command and get server response.
clientSocket.send('QUIT\r\n'.encode())
# close
clientSocket.close()
结果: