#!/usr/bin/env bash # Configure Beszel (PocketBase) SMTP for Mailcow alerts mailbox. # # Prerequisite: admin account created at http://10.0.10.22:8090 # # Usage: # export BESZEL_URL=http://10.0.10.22:8090 # export BESZEL_EMAIL=you@example.com # export BESZEL_PASSWORD='your-beszel-password' # export SMTP_PASS='alerts@ mailbox password' # or source .env # ./scripts/beszel-setup-smtp.sh # # Optional: SMTP_TO for test email (default idobkin@gmail.com) set -euo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" BESZEL_URL="${BESZEL_URL:-http://10.0.10.22:8090}" BESZEL_EMAIL="${BESZEL_EMAIL:-}" BESZEL_PASSWORD="${BESZEL_PASSWORD:-}" SMTP_HOST="${SMTP_HOST:-mail.levkine.ca}" SMTP_PORT="${SMTP_PORT:-587}" SMTP_USER="${SMTP_USER:-alerts@levkine.ca}" SMTP_PASS="${SMTP_PASS:-}" SMTP_TO="${SMTP_TO:-idobkin@gmail.com}" if [[ -f "${REPO_ROOT}/.env" ]]; then # shellcheck disable=SC1091 set -a source "${REPO_ROOT}/.env" set +a SMTP_PASS="${SMTP_PASS:-${ALERTS_PASSWORD:-}}" fi if [[ -z "${BESZEL_EMAIL}" || -z "${BESZEL_PASSWORD}" ]]; then echo "Set BESZEL_EMAIL and BESZEL_PASSWORD (Beszel admin you just created)" >&2 exit 1 fi if [[ -z "${SMTP_PASS}" ]]; then echo "Set SMTP_PASS or ALERTS_PASSWORD (alerts@levkine.ca mailbox password)" >&2 exit 1 fi export BESZEL_URL BESZEL_EMAIL BESZEL_PASSWORD SMTP_HOST SMTP_PORT SMTP_USER SMTP_PASS SMTP_TO "${REPO_ROOT}/.venv/bin/python3" <<'PY' import json import os import sys import urllib.error import urllib.request base = os.environ["BESZEL_URL"].rstrip("/") email = os.environ["BESZEL_EMAIL"] password = os.environ["BESZEL_PASSWORD"] smtp_host = os.environ["SMTP_HOST"] smtp_port = int(os.environ["SMTP_PORT"]) smtp_user = os.environ["SMTP_USER"] smtp_pass = os.environ["SMTP_PASS"] smtp_to = os.environ["SMTP_TO"] def req(method, path, token=None, body=None): url = f"{base}{path}" data = None headers = {"Content-Type": "application/json"} if body is not None: data = json.dumps(body).encode() if token: headers["Authorization"] = token request = urllib.request.Request(url, data=data, headers=headers, method=method) try: with urllib.request.urlopen(request, timeout=30) as resp: raw = resp.read().decode() return resp.status, json.loads(raw) if raw else {} except urllib.error.HTTPError as e: raw = e.read().decode() print(f"HTTP {e.code} {path}: {raw}", file=sys.stderr) raise print(f"Login to Beszel at {base} as {email}...") for collection in ("_superusers", "users"): try: status, auth = req( "POST", f"/api/collections/{collection}/auth-with-password", body={"identity": email, "password": password}, ) token = auth.get("token") if token: print(f"Login OK ({collection})") break except urllib.error.HTTPError: token = None continue else: print("Login failed: check BESZEL_EMAIL and BESZEL_PASSWORD", file=sys.stderr) sys.exit(1) print("Configuring SMTP (Mailcow STARTTLS)...") req( "PATCH", "/api/settings", token=token, body={ "smtp": { "enabled": True, "host": smtp_host, "port": smtp_port, "username": smtp_user, "password": smtp_pass, "tls": False, "authMethod": "PLAIN", "localName": "monitoring.levkin.ca", }, "meta": { "senderName": "Beszel", "senderAddress": smtp_user, }, }, ) print("SMTP settings saved") print(f"Sending test email to {smtp_to}...") req( "POST", "/api/settings/test/email", token=token, body={"email": smtp_to, "template": "verification", "collection": "_superusers"}, ) print("Test email request accepted — check inbox (and restart beszel if alerts fail later)") print("\nDone. Restart hub to avoid cached mail client issues:") print(" ssh root@10.0.10.22 'cd /opt/monitoring && docker compose restart beszel'") PY