Python logging模块SMTPHandler报socket.gaierror错误如何解决?
问题描述
尝试使用Python logging模块的SMTPHandler类发送日志邮件时,出现socket.gaierror: [Errno 11001] getaddrinfo failed错误,但相同的邮件服务器参数在直接使用smtplib时可以正常发送邮件,单独调用socket.getaddrinfo也能解析出IP地址。
报错信息
--- Logging error --- Traceback (most recent call last): File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\logging\handlers.py", line 1075, in emit smtp = smtplib.SMTP(self.mailhost, port, timeout=self.timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\smtplib.py", line 255, in __init__ (code, msg) = self.connect(host, port) ^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\smtplib.py", line 341, in connect self.sock = self._get_socket(host, port, self.timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\smtplib.py", line 312, in _get_socket return socket.create_connection((host, port), timeout, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\socket.py", line 827, in create_connection for res in getaddrinfo(host, port, 0, SOCK_STREAM): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\socket.py", line 962, in getaddrinfo for res in _socket.getaddrinfo(host, port, family, type, proto, flags): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ socket.gaierror: [Errno 11001] getaddrinfo failed Call stack: File "<string>", line 1, in <module> File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\idlelib\run.py", line 165, in main ret = method(*args, **kwargs) File "C:\Users\User\AppData\Local\Programs\Python\Python311\Lib\idlelib\run.py", line 579, in runcode exec(code, self.locals) File "C:\Users\User\Desktop\test_log\test_log.py", line 34, in <module> main() File "C:\Users\User\Desktop\test_log\test_log.py", line 28, in main log.critical('Testing email logging') Message: 'Testing email logging' Arguments: ()
配置与代码
日志处理器JSON配置
"emailhand": { "class": "logging.handlers.SMTPHandler", "level": "CRITICAL", "formatter": "a_formatter", "mailhost": "('send.smtp.com', 25)", "credentials": "('login@email.co.uk', 'password')", "fromaddr": "sender@email.co.uk", "toaddrs": "recipient@email.co.uk", "subject": "Test Log", "secure": "()", "timeout": 10.0 }
Python代码
import os import json import logging import logging.config import logging.handlers def init_logging(): logfile = r'C:\Users\User\Desktop\test_log\test_log.log' with open(r'C:\Users\User\Desktop\test_log\file-data\logging.json', 'r') as f: LOGGING_CONFIG = json.load(f) logging.config.dictConfig(LOGGING_CONFIG) def main(): init_logging() log = logging.getLogger('test_log') log.info('Some info from the main function') log.critical('Testing email logging') if __name__ == "__main__": main()
问题原因
核心问题出在JSON配置的格式上:
mailhost、credentials、secure被设置为字符串形式的Python元组(比如"('send.smtp.com', 25)"),但logging.config.dictConfig只会将JSON值解析为基础类型(字符串、数字、列表、字典),不会自动把字符串解析成Python元组。- 这导致SMTPHandler拿到的
mailhost是完整的字符串"('send.smtp.com', 25)",而不是预期的(host, port)元组。当smtplib尝试将这个字符串作为主机名解析时,自然会出现getaddrinfo失败的错误。
解决方法
修改JSON配置,将需要传递元组的参数改为JSON数组(因为JSON没有元组类型,数组会被dictConfig解析为Python列表,而SMTPHandler接受列表/元组作为这些参数的输入):
"emailhand": { "class": "logging.handlers.SMTPHandler", "level": "CRITICAL", "formatter": "a_formatter", "mailhost": ["send.smtp.com", 25], "credentials": ["login@email.co.uk", "password"], "fromaddr": "sender@email.co.uk", "toaddrs": "recipient@email.co.uk", "subject": "Test Log", "secure": [], "timeout": 10.0 }
补充说明
- 如果不需要
secure参数,可以直接删除该配置项,或者设置为null(对应Python的None)。 - 对于SSL连接(端口465),只需将
mailhost的端口改为465,并确保邮件服务器支持该端口的SSL连接即可,无需修改其他配置结构。
内容的提问来源于stack exchange,提问作者dabo_tusev
相关产品推荐
相关产品推荐

