python - ConnectionResetError: [WinError 10054] 现有连接被远程主机 (SMTP) 强行关闭
问题描述
我正在尝试使用 SMTP 套接字从一个 gmail 帐户向另一个帐户发送一封测试电子邮件。我已允许来自我的客户 gmail 帐户的不安全访问。
在登录阶段,代码在这里中断:
#Send username as Base64 encoded string
username = (username + '\r\n').encode()
command = base64.b64encode(username)
clientSocket.send(command)
resp = clientSocket.recv(1024)
print('S: ' + resp.decode())
我收到 10054 错误消息,并尝试使用 wireshark 分解发生的事情,但我并不真正了解发生了什么。它似乎是基于 google smtp 服务器的服务器端加密。我是套接字编程的新手,感谢您的耐心等待!
其余代码:
from socket import *
import time
import base64
print("")
username = input("Enter your mail.com username : ")
password = input("Enter your mail.com password : ")
rec = input("\nEnter the recipient's email address : ")
name = input("\nEnter your name : ")
subject = input("\nEnter the subject for your mail : \n")
message = ["SMTP client is awesome \r\n", "123456789 \r\n","Networking is cool. \r\n"]
print("")
endmsg = "\r\n.\r\n"
# Choose a mail server (e.g. Google mail server) and call it mailserver
mailserver = "smtp.gmail.com"
mailserverPort = 587
# Create socket called clientSocket and establish a TCP connection with mailserver
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((mailserver, mailserverPort))
resp = clientSocket.recv(1024)
print('S: ' + resp.decode())
# Send EHLO (for Extended SMTP) command and print server response.
heloCommand = 'EHLO 127.0.0.1 \r\n'
print('C: ' + heloCommand)
clientSocket.send(heloCommand.encode())
resp = clientSocket.recv(1024)
print('S: ' + resp.decode())
# Authentication start mail server client
command = 'STARTTLS \r\n'
print('C: ' + command)
clientSocket.send(command.encode())
resp = clientSocket.recv(1024)
print('S: ' + resp.decode())
# Authentication required for the mail.com server I'm using
command = 'AUTH LOGIN \r\n'
print('C: ' + command)
clientSocket.send(command.encode())
resp = clientSocket.recv(1024)
print('S: ' + resp.decode())
# Send username as Base64 encoded string
username = (username + '\r\n').encode()
command = base64.b64encode(username)
#print('C: ' + command.decode())
clientSocket.send(command)
resp = clientSocket.recv(1024)
print('S: ' + resp.decode())
# Send password as Base64 encoded string
password = (password + '\r\n').encode()
command = base64.b64encode(password)
print('C: ' + command)
clientSocket.send(command)
resp = clientSocket.recv(1024)
print('S: ' + resp.decode())
# Send MAIL FROM command and print server response.
command = "MAIL FROM: <" + username + ">\r\n"
print('C: ' + command)
clientSocket.send(command)
resp = clientSocket.recv(1024)
print('S: ' + resp.decode())
# Send RCPT TO command and print(server resp.decode()onse.
command = "RCPT TO: <" + rec + ">\r\n"
print('C: ' + command)
clientSocket.send(command)
resp = clientSocket.recv(1024)
print('S: ' + resp.decode())
# Send DATA command and print server response.
command = "DATA\r\n"
print('C: ' + command)
clientSocket.send(command)
resp = clientSocket.recv(1024)
print('S: ' + resp.decode())
# Send message headers
# Gmail does not accept mail without headers to prevent spam
command = 'From: ' + name + ' <' + username + '>' + '\r\n'
print('C: ' + command)
clientSocket.send(command)
command = 'To: ' + rec + '\r\n'
print('C: ' + command)
clientSocket.send(command)
command = 'Date: ' + time.asctime( time.localtime(time.time()) ) + '\r\n'
print('C: ' + command)
clientSocket.send(command)
command = 'Subject: ' + subject + '\r\n'
print('C: ' + command)
clientSocket.send(command)
# Send message data.
clientSocket.send('\r\n')
for msg in message:
print('C: ' + msg)
clientSocket.send(msg)
# Message ends with a single period.
print('C: ' + endmsg)
clientSocket.send(endmsg)
# Send QUIT command and get server resp.decode()onse.
command = "QUIT\r\n"
print('C: ' + command)
clientSocket.send(command)
resp = clientSocket.recv(1024)
print('S: ' + resp.decode())
解决方案
该STARTTLS
命令请求启动 SSL/TLS 加密会话。但是您的代码中根本没有 SSL/TLS 逻辑。如果服务器回复成功STARTTLS
,则您的客户端必须启动并完成成功的 SSL/TLS 握手,然后才能发送任何进一步的 SMTP 命令。SSL/TLS 会话要求对这些命令(及其响应)进行加密。
由于您没有遵守协议,您将被强制断开连接。所以要么不要使用STARTTLS
(在这种情况下,你AUTH
可能会失败),或者在你的套接字上正确实施 SSL/TLS。
顺便说一句,您不应该启用对您的 Gmail 帐户的“不安全访问”。让Gmail 创建一个特定于应用程序的密码并使用它来代替您的真实密码。
推荐阅读
- bootstrap-4 - Bootstrap 4 Flexbox - 将多个列与对齐项目中心对齐
- reactjs - 反应钩子查询不更新状态更改
- c++ - 之后仍需要使用源对象时调用父移动赋值运算符
- networking - Ping 不适用于 mininet 上的脊叶拓扑
- java - Is it possible to combine spring boot @Value with javax.validation.constraints?
- python - 我如何将列表中的单词合并到每个索引中的新列表,存储旧列表中的 k 内容
- c# - .Net Core - 编辑 ListBoxFor - 未显示所选选项
- c - 在C中获得n个二进制的leftBits
- java - Spring Boot 安全 JwtAuthentication 和 OAuth 一起
- parallel-processing - 如何将多个参数传递给 Octave 中的并行操作?