## Copyright © 2026 Olaf Kolkman ## SPDX-License-Identifier: GPL-3.0-or-later from unittest.mock import patch from backend.app.services.email_service import send_password_reset_email, send_test_email, send_verification_email def test_send_verification_email_uses_smtp_settings(monkeypatch): from backend.app.core.config import settings monkeypatch.setattr(settings, 'smtp_host', 'smtp.example.com') monkeypatch.setattr(settings, 'smtp_port', 587) monkeypatch.setattr(settings, 'smtp_from', 'LinkLog ') monkeypatch.setattr(settings, 'smtp_username', 'mailer') monkeypatch.setattr(settings, 'smtp_password', 'secret') monkeypatch.setattr(settings, 'smtp_use_tls', True) monkeypatch.setattr(settings, 'public_url', 'https://linklog.example') with patch('backend.app.services.email_service.SMTP') as smtp_class: smtp = smtp_class.return_value.__enter__.return_value send_verification_email('user@example.com', 'user', 'https://linklog.example/verify') smtp_class.assert_called_once_with('smtp.example.com', 587, timeout=10) smtp.starttls.assert_called_once_with() smtp.login.assert_called_once_with('mailer', 'secret') message = smtp.send_message.call_args.args[0] assert message['To'] == 'user@example.com' assert 'https://linklog.example/verify' in message.get_body(preferencelist=('plain',)).get_content() html = message.get_body(preferencelist=('html',)).get_content() assert 'cid:linklog-logo' in html assert 'width="50" height="50"' in html assert 'font-family:\'Asset\',Georgia,serif' in html assert 'Hello, a message from' in html assert 'vertical-align:top' in html assert 'padding:20px 0 20px 12px' in html assert 'font-size:18px' in html assert 'href="https://linklog.example"' in html assert '>linklog.example' in html assert any( part.get_content_type() == 'image/svg+xml' and part['Content-ID'] == '' for part in message.walk() ) def test_send_test_email_uses_configured_recipient(monkeypatch): from backend.app.core.config import settings monkeypatch.setattr(settings, 'smtp_host', 'smtp.example.com') monkeypatch.setattr(settings, 'smtp_from', 'LinkLog ') with patch('backend.app.services.email_service.SMTP') as smtp_class: smtp = smtp_class.return_value.__enter__.return_value send_test_email('admin@example.com') message = smtp.send_message.call_args.args[0] assert message['To'] == 'admin@example.com' assert message['Subject'] == 'LinkLog SMTP test' assert message.get_body(preferencelist=('html',)) is not None def test_password_reset_email_escapes_html_and_includes_logo(monkeypatch): from backend.app.core.config import settings monkeypatch.setattr(settings, 'smtp_host', 'smtp.example.com') monkeypatch.setattr(settings, 'smtp_from', 'LinkLog ') with patch('backend.app.services.email_service.SMTP') as smtp_class: smtp = smtp_class.return_value.__enter__.return_value send_password_reset_email('user@example.com', '', 'https://linklog.example/reset?x=1&y=2') message = smtp.send_message.call_args.args[0] html = message.get_body(preferencelist=('html',)).get_content() assert '<User>' in html assert 'x=1&y=2' in html assert 'cid:linklog-logo' in html def test_smtp_password_is_encrypted_at_rest(): from backend.app.services.email_service import get_smtp_settings, save_smtp_settings from backend.app.database import get_connection values = { 'smtp_host': 'smtp.example.com', 'smtp_port': 587, 'smtp_username': 'mailer', 'smtp_password': 'secret', 'smtp_from': 'LinkLog ', 'smtp_use_tls': True, } save_smtp_settings(values) with get_connection() as conn: stored = conn.execute('SELECT value FROM app_settings WHERE name = ?', ('smtp',)).fetchone()['value'] assert 'secret' not in stored assert get_smtp_settings()['smtp_password'] == 'secret'