From c0bd7b8f8121f072e596c60639a2cc7723ddaab9 Mon Sep 17 00:00:00 2001 From: Manu Date: Thu, 2 Jul 2026 17:33:54 +0200 Subject: [PATCH] catch SMTPException and TimeoutError in SMTP config flow (#175369) --- homeassistant/components/smtp/config_flow.py | 10 +++++++--- homeassistant/components/smtp/strings.json | 1 + tests/components/smtp/test_config_flow.py | 6 +++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/smtp/config_flow.py b/homeassistant/components/smtp/config_flow.py index 86c21e2de63d..b38cfef48c85 100644 --- a/homeassistant/components/smtp/config_flow.py +++ b/homeassistant/components/smtp/config_flow.py @@ -1,8 +1,9 @@ """Config flow for the SMTP integration.""" from collections.abc import Mapping +from contextlib import suppress import logging -from smtplib import SMTP, SMTP_SSL, SMTPAuthenticationError +from smtplib import SMTP, SMTP_SSL, SMTPAuthenticationError, SMTPException import socket from ssl import SSLCertVerificationError from typing import Any, override @@ -310,18 +311,21 @@ def validate_input(user_input: dict[str, Any]) -> dict[str, str]: if user_input.get(CONF_USERNAME) and user_input.get(CONF_PASSWORD): mail.login(user_input[CONF_USERNAME], user_input[CONF_PASSWORD]) + except TimeoutError: + errors["base"] = "timeout_connect" except SMTPAuthenticationError: errors["base"] = "invalid_auth" except SSLCertVerificationError: errors["base"] = "invalid_cert" - except socket.gaierror, ConnectionRefusedError: + except socket.gaierror, ConnectionRefusedError, SMTPException: errors["base"] = "cannot_connect" except Exception: _LOGGER.exception("Unexpected exception") errors["base"] = "unknown" finally: if mail is not None: - mail.quit() + with suppress(SMTPException): + mail.quit() return errors diff --git a/homeassistant/components/smtp/strings.json b/homeassistant/components/smtp/strings.json index 5f3d7cc25bb1..1c6a8cf6c2c5 100644 --- a/homeassistant/components/smtp/strings.json +++ b/homeassistant/components/smtp/strings.json @@ -9,6 +9,7 @@ "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", "invalid_cert": "Invalid certificate", + "timeout_connect": "[%key:common::config_flow::error::timeout_connect%]", "unknown": "[%key:common::config_flow::error::unknown%]" }, "step": { diff --git a/tests/components/smtp/test_config_flow.py b/tests/components/smtp/test_config_flow.py index c8180204ed32..0767acbe0546 100644 --- a/tests/components/smtp/test_config_flow.py +++ b/tests/components/smtp/test_config_flow.py @@ -1,6 +1,6 @@ """Test the SMTP config flow.""" -from smtplib import SMTPAuthenticationError +from smtplib import SMTPAuthenticationError, SMTPServerDisconnected from socket import gaierror from ssl import SSLCertVerificationError from unittest.mock import AsyncMock, MagicMock @@ -104,6 +104,8 @@ async def test_form_already_configured( [ (SMTPAuthenticationError(0, ""), "invalid_auth"), (ConnectionRefusedError, "cannot_connect"), + (TimeoutError, "timeout_connect"), + (SMTPServerDisconnected, "cannot_connect"), (gaierror, "cannot_connect"), (SSLCertVerificationError, "invalid_cert"), (ValueError, "unknown"), @@ -286,6 +288,8 @@ async def test_form_reconfigure_already_configured( [ (SMTPAuthenticationError(0, ""), "invalid_auth"), (ConnectionRefusedError, "cannot_connect"), + (SMTPServerDisconnected, "cannot_connect"), + (TimeoutError, "timeout_connect"), (gaierror, "cannot_connect"), (SSLCertVerificationError, "invalid_cert"), (ValueError, "unknown"),