agf*_*ing 9 python email timeout smtplib
我有一个需要无限期运行的脚本。该脚本设置为通过电子邮件向我发送每天已完成的某些步骤的确认信息。我正在尝试为此使用 smtplib。
初始连接已设置,以便我将在脚本启动时使用 getpass 输入我的登录名(写入脚本)和密码。我不想将我的密码写入脚本中,甚至不想让脚本在配置文件中引用。因此,我想在启动时输入密码并保留 smtp 连接。
按照脚本中的要求重新连接到 smtp 连接将无法完全脱离脚本并让它无限期运行。
我目前正在使用的示例代码如下所示:
import smtplib
import getpass
smtpObj = smtplib.SMTP('smtp.gmail.com',587)
smtpObj.ehlo()
smtpObj.starttls()
smtpObj.login('myemail@gmail.com',password = getpass.getpass('Enter Password: '))
Run Code Online (Sandbox Code Playgroud)
然后我输入密码,输出是:
(235, b'2.7.0 Accepted')
Run Code Online (Sandbox Code Playgroud)
所以这一切正常。
问题是脚本需要根据时间暂停几分钟到几天不等。这是使用带有时间条件的 while 循环来实现的,直到调用发送函数的某个时间:
smtpObj.sendmail('myemail@gmail.com','recipient@gmail.com','This is a test')
Run Code Online (Sandbox Code Playgroud)
然而,经过大约 20/30 分钟的时间后,似乎(即,如果暂停就足够了)。然后 smptObj.sendmail 调用将由于超时错误而失败。
具体错误如下:
SMTPSenderRefused: (451, b'4.4.2 Timeout - closing connection. l22sm2469172wre.52 - gsmtp', 'myemail@gmail.com')
Run Code Online (Sandbox Code Playgroud)
到目前为止,我已经尝试了以下方法:
使用以下超时参数化实例化连接对象:
smtpObj = smtplib.SMTP('smtp.gmail.com',587,timeout=None)
smtpObj = smtplib.SMTP('smtp.gmail.com',587,timeout=86400)
Run Code Online (Sandbox Code Playgroud)
这些似乎都没有抑制连接的“超时”(即同样的问题仍然存在)。
我也尝试过这篇文章中建议的这种解决方案:
如何使用 smtplib 和 Python 打开 SMTP 连接?
然而,这也没有奏效!
我确实想尝试避免每次发送电子邮件时都必须重新连接的解决方案,因为我只想手动输入一次连接密码,而不是将其写入直接或间接编写脚本。
肯定有办法处理超时问题!如果有人可以在这里提供帮助,请告诉我!不过,如果您认为在脚本需要发送电子邮件之前重新连接的更“明显”解决方案是更好的方法,那么请告诉我。
谢谢!...
如果您不想在脚本中包含敏感凭据,则应使用 env vars。
从终端外壳(python 之外):
$ EXPORT secretVariable=mySecretValue
$ echo $secretVariable
$ mySecretValue
$
Run Code Online (Sandbox Code Playgroud)
因此,要在您的代码中利用这一点...
>>> import os
>>> myPW = os.getenv('secretVariable')
>>> myPW
'mySecretVal'
>>>
Run Code Online (Sandbox Code Playgroud)
通过这样做,您不必手动输入密码。除此之外,尝试一次将空闲的 SMTP 连接打开几天是不太实际的,只需实现一个 try/except 结构..
import smtplib
import os
def smtp_connect():
# Instantiate a connection object...
password = os.getenv('secretVariable')
smtpObj = smtplib.SMTP('smtp.gmail.com',587)
smtpObj.ehlo()
smtpObj.starttls()
smtpObj.login('myemail@gmail.com',password=password)
return smtpObj
def smtp_operations():
try:
# SMTP lib operations...
smtpObj.sendmail('myemail@gmail.com','recipient@gmail.com','This is a test')
# SMTP lib operations...
except Exception: # replace this with the appropriate SMTPLib exception
# Overwrite the stale connection object with a new one
# Then, re-attempt the smtp_operations() method (now that you have a fresh connection object instantiated).
smtpObj = smtp_connect()
smtp_operations()
smtpObj = smtp_connect()
smtp_operations()
Run Code Online (Sandbox Code Playgroud)
通过替换except Exception为在Exception连接陈旧时引发的实际 SMTP ,您将确保不会捕获与连接陈旧无关的异常。
因此,使用try/except,脚本将尝试执行 SMTP 操作。如果连接是陈旧的,它将实例化一个新的连接对象,然后尝试使用新的连接对象重新执行自己。