chore: remove smtp_config.py - no longer needed, ns8-sendmail handles relay
This commit is contained in:
@@ -1,189 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
smtp_config.py - Reads the SMTP relay configuration from NS8 cluster Redis.
|
|
||||||
|
|
||||||
NS8 stores the mail relay settings (configured via the 'Mail relay' panel or
|
|
||||||
the `mail` module) in Redis under:
|
|
||||||
|
|
||||||
cluster/mail_settings (hash) - fields: relay_host, relay_port, relay_tls,
|
|
||||||
relay_username, relay_password,
|
|
||||||
mail_domain, mail_from
|
|
||||||
|
|
||||||
This module reads those values and returns a dict compatible with the
|
|
||||||
`smtp` and `mail` sections expected by notifier.py, so that ns8-backup-monitor
|
|
||||||
always uses the same relay that NS8 itself uses for system notifications.
|
|
||||||
|
|
||||||
Fallback chain:
|
|
||||||
1. NS8 Redis SMTP config (cluster/mail_settings)
|
|
||||||
2. config.yml [smtp] section
|
|
||||||
3. localhost:25 unauthenticated
|
|
||||||
"""
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import subprocess
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# NS8 Redis key for global mail relay settings
|
|
||||||
NS8_MAIL_SETTINGS_KEY = "cluster/mail_settings"
|
|
||||||
|
|
||||||
# Alternative key used by some NS8 versions / mail module
|
|
||||||
NS8_MAIL_SETTINGS_ALT = "module/mail1/settings"
|
|
||||||
|
|
||||||
|
|
||||||
def _redis_hgetall(socket: str, key: str) -> dict:
|
|
||||||
"""Read a Redis hash as a dict via redis-cli."""
|
|
||||||
cmd = ["redis-cli", "-s", socket, "HGETALL", key]
|
|
||||||
try:
|
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
|
|
||||||
lines = [l for l in result.stdout.strip().splitlines() if l]
|
|
||||||
return dict(zip(lines[::2], lines[1::2]))
|
|
||||||
except Exception as e:
|
|
||||||
log.warning(f"redis-cli HGETALL {key} failed: {e}")
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
def _try_keys(socket: str) -> dict:
|
|
||||||
"""Try the known NS8 Redis keys for mail settings, return first non-empty."""
|
|
||||||
for key in (NS8_MAIL_SETTINGS_KEY, NS8_MAIL_SETTINGS_ALT):
|
|
||||||
fields = _redis_hgetall(socket, key)
|
|
||||||
if fields:
|
|
||||||
log.info(f"Found NS8 SMTP config at Redis key: {key}")
|
|
||||||
return fields
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
def load_ns8_smtp(config: dict) -> Optional[dict]:
|
|
||||||
"""
|
|
||||||
Read NS8 SMTP relay config from Redis.
|
|
||||||
|
|
||||||
Returns a dict with keys:
|
|
||||||
smtp.host, smtp.port, smtp.use_tls, smtp.use_starttls,
|
|
||||||
smtp.username, smtp.password,
|
|
||||||
mail.from (system sender address)
|
|
||||||
|
|
||||||
Returns None if not found or Redis is unreachable.
|
|
||||||
"""
|
|
||||||
socket = config.get("redis", {}).get(
|
|
||||||
"socket", "/var/lib/nethserver/cluster/state/redis.sock"
|
|
||||||
)
|
|
||||||
fields = _try_keys(socket)
|
|
||||||
|
|
||||||
if not fields:
|
|
||||||
log.debug("No NS8 mail settings found in Redis")
|
|
||||||
return None
|
|
||||||
|
|
||||||
# NS8 field names (may vary by version — we handle both snake_case and camelCase)
|
|
||||||
host = (
|
|
||||||
fields.get("relay_host")
|
|
||||||
or fields.get("relayHost")
|
|
||||||
or fields.get("smarthost")
|
|
||||||
or ""
|
|
||||||
).strip()
|
|
||||||
|
|
||||||
if not host:
|
|
||||||
log.debug("NS8 mail settings found in Redis but relay_host is empty (direct delivery)")
|
|
||||||
return None
|
|
||||||
|
|
||||||
try:
|
|
||||||
port = int(
|
|
||||||
fields.get("relay_port")
|
|
||||||
or fields.get("relayPort")
|
|
||||||
or fields.get("smarthost_port")
|
|
||||||
or 587
|
|
||||||
)
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
port = 587
|
|
||||||
|
|
||||||
# TLS flags - NS8 stores as string 'true'/'false' or '1'/'0'
|
|
||||||
def _bool(val) -> bool:
|
|
||||||
return str(val).lower() in ("true", "1", "yes")
|
|
||||||
|
|
||||||
use_tls = _bool(
|
|
||||||
fields.get("relay_tls") or fields.get("tls") or fields.get("relayTls") or False
|
|
||||||
)
|
|
||||||
# STARTTLS is the default for port 587; detect from port if not explicit
|
|
||||||
use_starttls = _bool(
|
|
||||||
fields.get("relay_starttls")
|
|
||||||
or fields.get("starttls")
|
|
||||||
or fields.get("relayStarttls")
|
|
||||||
or (port == 587 and not use_tls)
|
|
||||||
)
|
|
||||||
|
|
||||||
username = (
|
|
||||||
fields.get("relay_username")
|
|
||||||
or fields.get("relayUsername")
|
|
||||||
or fields.get("username")
|
|
||||||
or ""
|
|
||||||
).strip()
|
|
||||||
password = (
|
|
||||||
fields.get("relay_password")
|
|
||||||
or fields.get("relayPassword")
|
|
||||||
or fields.get("password")
|
|
||||||
or ""
|
|
||||||
).strip()
|
|
||||||
|
|
||||||
mail_from = (
|
|
||||||
fields.get("mail_from")
|
|
||||||
or fields.get("mailFrom")
|
|
||||||
or fields.get("sender")
|
|
||||||
or f"ns8-backup-monitor@{fields.get('mail_domain', 'localhost')}"
|
|
||||||
).strip()
|
|
||||||
|
|
||||||
result = {
|
|
||||||
"smtp": {
|
|
||||||
"host": host,
|
|
||||||
"port": port,
|
|
||||||
"use_tls": use_tls,
|
|
||||||
"use_starttls": use_starttls,
|
|
||||||
"username": username,
|
|
||||||
"password": password,
|
|
||||||
},
|
|
||||||
"mail_from": mail_from,
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info(
|
|
||||||
f"NS8 SMTP relay: {host}:{port} "
|
|
||||||
f"tls={use_tls} starttls={use_starttls} "
|
|
||||||
f"auth={'yes' if username else 'no'} "
|
|
||||||
f"from={mail_from}"
|
|
||||||
)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_smtp_config(config: dict) -> tuple:
|
|
||||||
"""
|
|
||||||
Resolve the effective SMTP configuration using the fallback chain:
|
|
||||||
1. NS8 Redis cluster/mail_settings
|
|
||||||
2. config.yml [smtp] + [mail] sections
|
|
||||||
3. localhost:25 unauthenticated (last resort)
|
|
||||||
|
|
||||||
Returns (smtp_cfg: dict, mail_from: str).
|
|
||||||
smtp_cfg keys: host, port, use_tls, use_starttls, username, password
|
|
||||||
"""
|
|
||||||
# Try NS8 Redis first, unless explicitly disabled in config
|
|
||||||
use_ns8_smtp = config.get("smtp", {}).get("use_ns8_relay", True)
|
|
||||||
|
|
||||||
if use_ns8_smtp:
|
|
||||||
ns8 = load_ns8_smtp(config)
|
|
||||||
if ns8:
|
|
||||||
# Merge: NS8 provides smtp + mail_from, but mail.to still comes from config.yml
|
|
||||||
smtp_cfg = ns8["smtp"]
|
|
||||||
mail_from = config.get("mail", {}).get("from") or ns8["mail_from"]
|
|
||||||
return smtp_cfg, mail_from
|
|
||||||
else:
|
|
||||||
log.info("NS8 SMTP config not available, falling back to config.yml smtp section")
|
|
||||||
else:
|
|
||||||
log.info("NS8 relay lookup disabled (smtp.use_ns8_relay: false), using config.yml")
|
|
||||||
|
|
||||||
# Fallback: config.yml
|
|
||||||
smtp_cfg = config.get("smtp", {})
|
|
||||||
mail_from = config.get("mail", {}).get("from", "ns8-backup-monitor@localhost")
|
|
||||||
|
|
||||||
if not smtp_cfg.get("host"):
|
|
||||||
log.warning("No SMTP host configured in config.yml, falling back to localhost:25")
|
|
||||||
smtp_cfg = {"host": "localhost", "port": 25, "use_tls": False,
|
|
||||||
"use_starttls": False, "username": "", "password": ""}
|
|
||||||
|
|
||||||
return smtp_cfg, mail_from
|
|
||||||
Reference in New Issue
Block a user