"""Unit tests for SMTP mail helpers.""" from __future__ import annotations import smtplib import unittest from types import SimpleNamespace from unittest.mock import MagicMock, patch from media_library_viewer_api.services.mailer import ( EmailAttachment, describe_smtp_error, html_to_text, send_email_message, ) class _SMTPContext: def __init__(self, smtp: MagicMock): self.smtp = smtp def __enter__(self): return self.smtp def __exit__(self, exc_type, exc, tb): return False class MailerTests(unittest.TestCase): def test_html_to_text_strips_tags(self) -> None: text = html_to_text("
Hello world
Line 2
") self.assertIn("Hello", text) self.assertIn("world", text) self.assertIn("Line 2", text) def test_send_email_message_uses_smtp_with_attachments(self) -> None: settings = SimpleNamespace( smtp_host="smtp.example.com", smtp_port=587, smtp_username="mailer@example.com", smtp_password="secret", smtp_from_address="mailer@example.com", smtp_from_name="Manage", smtp_use_tls=True, smtp_use_ssl=False, smtp_timeout=15, ) smtp = MagicMock() smtp.send_message.return_value = {} smtp_factory = MagicMock(return_value=_SMTPContext(smtp)) with patch("media_library_viewer_api.services.mailer.smtplib.SMTP", smtp_factory), patch( "media_library_viewer_api.services.mailer.smtplib.SMTP_SSL" ) as smtp_ssl: result = send_email_message( settings, recipients=["alex@example.com", "sam@example.com"], subject="Hello", html_body="Hi there
", attachments=[EmailAttachment(filename="note.txt", content_type="text/plain", data=b"note")], ) smtp_ssl.assert_not_called() smtp.starttls.assert_called_once() smtp.login.assert_called_once_with("mailer@example.com", "secret") smtp.send_message.assert_called_once() message = smtp.send_message.call_args.args[0] self.assertEqual(message["Subject"], "Hello") self.assertEqual(message["From"], "ManageHello
", ) self.assertEqual(result["selected_mode"]["label"], "Fastmail STARTTLS 587") self.assertEqual(result["authenticated_as"], "mailer@example.com") self.assertEqual(len(result["attempts"]), 2) self.assertEqual(result["attempts"][0]["status"], "failed") self.assertEqual(result["attempts"][1]["status"], "ok") fallback_smtp.send_message.assert_called_once() def test_send_email_message_retries_with_smtp_username_when_from_is_rejected(self) -> None: settings = SimpleNamespace( smtp_host="smtp.example.com", smtp_port=587, smtp_username="mailer@example.com", smtp_password="secret", smtp_from_address="alias@example.com", smtp_from_name="Manage", smtp_use_tls=True, smtp_use_ssl=False, smtp_timeout=15, ) smtp = MagicMock() smtp.send_message.side_effect = [ smtplib.SMTPDataError(551, b"5.7.1 Not authorised to send from this header address"), {}, ] smtp_factory = MagicMock(return_value=_SMTPContext(smtp)) with patch("media_library_viewer_api.services.mailer.smtplib.SMTP", smtp_factory), patch( "media_library_viewer_api.services.mailer.smtplib.SMTP_SSL" ) as smtp_ssl: result = send_email_message( settings, recipients=["alex@example.com"], subject="Hello", html_body="Hello
", ) smtp_ssl.assert_not_called() self.assertEqual(result["from_address"], "mailer@example.com") self.assertEqual(smtp.send_message.call_count, 2) first_message = smtp.send_message.call_args_list[0].args[0] second_message = smtp.send_message.call_args_list[1].args[0] self.assertEqual(first_message["From"], "Manage