added backends, improved templating, rbac

This commit is contained in:
2026-06-10 14:40:22 +02:00
parent d9ca48addc
commit ce43f2658f
28 changed files with 1183 additions and 78 deletions

View File

@@ -18,6 +18,14 @@ class SmtpSendError(RuntimeError):
"""Raised when an SMTP send attempt fails."""
@dataclass(frozen=True, slots=True)
class SmtpLoginTestResult:
host: str
port: int
security: str
authenticated: bool
@dataclass(frozen=True, slots=True)
class SmtpSendResult:
host: str
@@ -80,6 +88,34 @@ def _decode_refused(refused: dict[str, tuple[int, bytes]]) -> dict[str, tuple[in
return normalized
def test_smtp_login(*, smtp_config: SmtpConfig) -> SmtpLoginTestResult:
"""Open an SMTP connection and authenticate if credentials are configured.
This is intentionally side-effect free: it does not send a message and it
never receives envelope or recipient data. It is used by the WebUI to check
whether the configured transport can be reached before a campaign is built
or queued.
"""
host, port = _require_smtp_config(smtp_config)
smtp = _open_smtp(smtp_config)
try:
return SmtpLoginTestResult(
host=host,
port=port,
security=smtp_config.security.value,
authenticated=bool(smtp_config.username and smtp_config.password),
)
finally:
try:
smtp.quit()
except Exception:
try:
smtp.close()
except Exception:
pass
def prepare_test_message(
message: EmailMessage,
*,