diff --git a/homeassistant/components/smtp/notify.py b/homeassistant/components/smtp/notify.py index 4f887ae3b448..325f121575e3 100644 --- a/homeassistant/components/smtp/notify.py +++ b/homeassistant/components/smtp/notify.py @@ -315,25 +315,37 @@ class MailNotificationService(SmtpClient, BaseNotificationService): def _send_email(self, msg: MIMEMultipart | MIMEText, recipients: list[str]) -> None: """Send the message.""" mail = self.connect() - for _ in range(self.tries): + for attempt in range(self.tries): try: mail.sendmail(self._sender, recipients, msg.as_string()) break - except SMTPServerDisconnected: + except SMTPServerDisconnected as e: + with suppress(SMTPException): + mail.quit() + if attempt == self.tries - 1: + _LOGGER.debug("Full exception:", exc_info=True) + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="send_mail_connection_error", + ) from e _LOGGER.warning( "SMTPServerDisconnected sending mail: retrying connection", exc_info=_LOGGER.isEnabledFor(logging.DEBUG), ) + mail = self.connect() + except SMTPException as e: with suppress(SMTPException): mail.quit() - mail = self.connect() - except SMTPException: + if attempt == self.tries - 1: + _LOGGER.debug("Full exception:", exc_info=True) + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="send_mail_connection_error", + ) from e _LOGGER.warning( "SMTPException sending mail: retrying connection", exc_info=_LOGGER.isEnabledFor(logging.DEBUG), ) - with suppress(SMTPException): - mail.quit() mail = self.connect() with suppress(SMTPException): mail.quit() diff --git a/tests/components/smtp/test_notify.py b/tests/components/smtp/test_notify.py index 3ebebfed260a..510013aa53a4 100644 --- a/tests/components/smtp/test_notify.py +++ b/tests/components/smtp/test_notify.py @@ -4,6 +4,7 @@ from pathlib import Path import re from smtplib import ( SMTPAuthenticationError, + SMTPException, SMTPHeloError, SMTPSenderRefused, SMTPServerDisconnected, @@ -16,6 +17,7 @@ from syrupy.assertion import SnapshotAssertion from homeassistant.components.notify import ( ATTR_MESSAGE, + ATTR_TARGET, DOMAIN as NOTIFY_DOMAIN, SERVICE_SEND_MESSAGE, ) @@ -360,3 +362,35 @@ async def test_notify_retry_on_disconnect_with_broken_quit( ) assert smtp.sendmail.call_count == 2 + + +@pytest.mark.parametrize("exception", [SMTPServerDisconnected, SMTPException]) +async def test_legacy_notify_exception( + hass: HomeAssistant, + config_entry: MockConfigEntry, + smtp: MagicMock, + exception: Exception, +) -> None: + """Test legacy notify action raises when retries are exhausted.""" + + config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + assert config_entry.state is ConfigEntryState.LOADED + + smtp.sendmail.side_effect = exception + + with pytest.raises(HomeAssistantError) as e: + await hass.services.async_call( + NOTIFY_DOMAIN, + "home_assistant", + { + ATTR_TARGET: ["recipient@example.com"], + ATTR_MESSAGE: "Hello World", + }, + blocking=True, + ) + + assert e.value.translation_key == "send_mail_connection_error" + assert smtp.sendmail.call_count == 2