About Multi-camera viewer optimized for RTSP streams
1import os
2import smtplib
3from email.message import EmailMessage
4from email.utils import formatdate
5
6
7DEFAULT_EMAIL_CONFIG = {
8 "enabled": False,
9 "smtp_host": "",
10 "smtp_port": 587,
11 "smtp_username": "",
12 "smtp_password": "",
13 "use_tls": True,
14 "from": "",
15 "to": [],
16}
17
18
19def send_detection_email(
20 config: dict | None,
21 subject: str,
22 body: str,
23 image_path: str | None = None,
24 require_enabled: bool = True,
25):
26 merged = dict(DEFAULT_EMAIL_CONFIG)
27 if config:
28 merged.update(config)
29 if require_enabled and not merged.get("enabled"):
30 return
31
32 host = str(merged.get("smtp_host") or "").strip()
33 recipients = merged.get("to") or []
34 if isinstance(recipients, str):
35 recipients = [recipients]
36 recipients = [str(item).strip() for item in recipients if str(item).strip()]
37 if not host:
38 raise ValueError("SMTP host fehlt")
39 if not recipients:
40 raise ValueError("Empfänger fehlt")
41
42 sender = str(merged.get("from") or merged.get("smtp_username") or "").strip()
43 if not sender:
44 raise ValueError("Absender fehlt")
45
46 msg = EmailMessage()
47 msg["Subject"] = subject
48 msg["From"] = sender
49 msg["To"] = ", ".join(recipients)
50 msg["Date"] = formatdate(localtime=True)
51 msg.set_content(body)
52
53 if image_path and os.path.exists(image_path):
54 with open(image_path, "rb") as fh:
55 msg.add_attachment(
56 fh.read(),
57 maintype="image",
58 subtype="jpeg",
59 filename=os.path.basename(image_path),
60 )
61
62 port = int(merged.get("smtp_port") or 587)
63 username = str(merged.get("smtp_username") or "").strip()
64 password = str(merged.get("smtp_password") or "")
65 with smtplib.SMTP(host, port, timeout=15) as smtp:
66 if merged.get("use_tls", True):
67 smtp.starttls()
68 if username:
69 smtp.login(username, password)
70 smtp.send_message(msg)