使用 Python 连接到 SMTP(SSL 或 TLS)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12854572/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 12:00:51  来源:igfitidea点击:

Connect to SMTP (SSL or TLS) using Python

pythonsocketssmtpgmail

提问by user1287523

I am attempting to connect to the Gmail SMTP mail server and perform tasks as outlined by the skeleton code given to me. Only the use of sockets is allowed (so not the smtplib). I need to: send HELOcommand, MAIL FROM, RCPT TO, and DATA.

我正在尝试连接到 Gmail SMTP 邮件服务器并执行给我的骨架代码所概述的任务。只socket允许使用s (所以不允许使用smtplib)。我需要:发送HELO命令MAIL FROMRCPT TO、 和DATA

There are many cases of similar problems posted, but they haven't received the proper answer. For example: Implementing Transport Layer Security in Python - Simple Mail Client

类似问题的案例已经发布了很多,但都没有得到正确的答案。例如: 在 Python 中实现传输层安全性 - 简单邮件客户端

The program is required to connect to smtp.gmail.comover port 587. I've taken two different approaches:

该程序需要smtp.gmail.com通过端口连接587。我采取了两种不同的方法:

  1. Using STARTTLS:

    mailserver = 'smtp.gmail.com'
    clientSocket = socket(AF_INET, SOCK_STREAM)
    clientSocket.connect((mailserver, 587))
    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.
    command = "STARTTLS\r\n"
    clientSocket.send(command)
    recvdiscard = clientSocket.recv(1024)
    print recvdiscard
    clientSocket.send("MAIL From: email\r\n")
    recv2 = clientSocket.recv(1024)
    print recv2
    if recv2[:3] != '250':
        print '250 reply not received from server.'
    
  2. Using SSL:

    clientSocketSSL = ssl.wrap_socket(clientSocket)
    

    Then clientSocketSSLreplaces all instances of clientSocket. The STARTTLS lines are also removed and import sslis added to the top.

  1. 使用 STARTTLS:

    mailserver = 'smtp.gmail.com'
    clientSocket = socket(AF_INET, SOCK_STREAM)
    clientSocket.connect((mailserver, 587))
    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.
    command = "STARTTLS\r\n"
    clientSocket.send(command)
    recvdiscard = clientSocket.recv(1024)
    print recvdiscard
    clientSocket.send("MAIL From: email\r\n")
    recv2 = clientSocket.recv(1024)
    print recv2
    if recv2[:3] != '250':
        print '250 reply not received from server.'
    
  2. 使用 SSL:

    clientSocketSSL = ssl.wrap_socket(clientSocket)
    

    然后clientSocketSSL替换 的所有实例clientSocket。STARTTLS 行也被删除并import ssl添加到顶部。

When using the first method, the MAIL FROM:command isn't returning anything. I'm getting the following output:

使用第一种方法时,该MAIL FROM:命令不返回任何内容。我得到以下输出:

250 mx.google.com at your service

220 2.0.0 Ready to start TLS

250 reply not received from server.

When using SSL, I'm getting the same as the linked post:

使用 SSL 时,我得到的与链接的帖子相同:

ssl.SSLError: [Errno 1] _ssl.c:504: error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol

Am I missing something here? I guess my best option is to use TLS but I have no idea how to go about that... is there something wrong with my MAIL FROMcommand?

我在这里错过了什么吗?我想我最好的选择是使用 TLS,但我不知道该怎么做……我的MAIL FROM命令有问题吗?

采纳答案by Aleksi Torhamo

When using SSL, you need to connect to port 465 instead of port 587. If you use STARTTLS, you still need to use ssl.wrap_socket, you just do it later - specifically, after receiving the 220response to the STARTTLScommand. After doing STARTTLS, you're supposed to do HELOagain, since the server is supposed to forget anything that happened before the STARTTLS.

使用SSL时,需要连接465端口而不是587端口。如果使用STARTTLS,仍然需要使用ssl.wrap_socket,以后再做——特别是在收到命令的220响应后STARTTLS。做完之后STARTTLS,你应该再做HELO一次,因为服务器应该忘记在STARTTLS.

In either case, the servers at smtp.google.com ports 465 and 587 still won't return a 250response to the MAILcommand, since they require that you are authenticated before you send mail. You'll get a 530response instead. You'll need to use the AUTHcommand with your gmail.com credentials to authenticate before you can use MAILsuccessfully on those servers.

在任何一种情况下,smtp.google.com 端口 465 和 587 上的服务器仍然不会返回250MAIL命令的响应,因为它们要求您在发送邮件之前进行身份验证。您会收到530回复。您需要使用AUTH带有 gmail.com 凭据的命令进行身份验证,然后才能MAIL在这些服务器上成功使用。

If you don't want to authenticate, and depending on the details of what you need to do, you could try using port 25 of the server found in gmail.com's MX record. At the moment, the server is gmail-smtp-in.l.google.com and supports STARTTLS.

如果您不想进行身份验证,并且根据您需要执行的操作的详细信息,您可以尝试使用在 gmail.com 的 MX 记录中找到的服务器的端口 25。目前,服务器为 gmail-smtp-in.l.google.com 并支持 STARTTLS。

回答by ChadJiang

After STARTTLS, call

之后STARTTLS,调用

clientSocket = ssl.wrap_socket(clientSocket)