From eace9bd85257ebb0e9d2d9f61cff0cb25f1dae28 Mon Sep 17 00:00:00 2001 From: ale <ale@incal.net> Date: Wed, 19 Mar 2025 11:10:54 +0000 Subject: [PATCH] Resolve the SMTP hostname on each connection Combined with randomization of multiple results, this allows Mailman to run simple round-robin balancing of the available SMTP servers. --- Mailman/Handlers/SMTPDirect.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Mailman/Handlers/SMTPDirect.py b/Mailman/Handlers/SMTPDirect.py index 2e5963ca..7a9e8315 100644 --- a/Mailman/Handlers/SMTPDirect.py +++ b/Mailman/Handlers/SMTPDirect.py @@ -28,6 +28,7 @@ for a threaded implementation. import copy import time +import random import socket import smtplib from base64 import b64encode @@ -55,13 +56,29 @@ except NameError: +# Resolve host/port, randomizing multiple IPs. +def _resolve(host, port): + results = [x[4] for x in socket.getaddrinfo( + host, port, + family=socket.AF_INET, + type=socket.SOCK_STREAM, + proto=socket.IPPROTO_TCP)] + return random.choice(results) + +# SMTP class that resolves the target randomly on each connection. +class SMTPRR(smtplib.SMTP): + + def _get_socket(self, host, port, timeout): + host, port = _resolve(host, port) + return socket.create_connection((host, port), timeout) + # Manage a connection to the SMTP server class Connection: def __init__(self): self.__conn = None def __connect(self): - self.__conn = smtplib.SMTP( + self.__conn = SMTPRR( local_hostname=mm_cfg.SMTP_HELO_HOST) self.__conn.set_debuglevel(mm_cfg.SMTPLIB_DEBUG_LEVEL) self.__conn.connect(mm_cfg.SMTPHOST, mm_cfg.SMTPPORT) -- GitLab