Files
homelab-optimized/scripts/lib/notify.py
Gitea Mirror Bot d72af152e3
Some checks failed
Documentation / Deploy to GitHub Pages (push) Has been cancelled
Documentation / Build Docusaurus (push) Has been cancelled
Sanitized mirror from private repository - 2026-04-16 07:19:56 UTC
2026-04-16 07:19:56 +00:00

96 lines
2.9 KiB
Python

"""Notification helpers — ntfy and SMTP via Proton Bridge."""
import imaplib
import logging
import smtplib
import ssl
import urllib.request
from datetime import datetime
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from zoneinfo import ZoneInfo
log = logging.getLogger(__name__)
SMTP_HOST = "127.0.0.1"
SMTP_PORT = 1025
SMTP_USER = "admin@thevish.io"
SMTP_PASS = "REDACTED_PASSWORD" # pragma: allowlist secret
DEFAULT_TO = "admin@thevish.io"
IMAP_HOST = "127.0.0.1"
IMAP_PORT = 1143
DIGEST_FOLDER = "Folders/Digests"
def send_ntfy(topic: str, title: str, message: str, priority: str = "default",
base_url: str = "https://ntfy.sh"):
"""Send a push notification via ntfy."""
url = f"{base_url.rstrip('/')}/{topic}"
try:
req = urllib.request.Request(url, data=message.encode(), headers={
"Title": title,
"Priority": priority,
"Content-Type": "text/plain",
})
with urllib.request.urlopen(req, timeout=10):
pass
log.info("ntfy sent: %s", title)
except Exception as e:
log.warning("ntfy failed: %s", e)
def _file_to_digests(msg_bytes: bytes):
"""File a copy of the message into the Digests folder via Proton Bridge IMAP."""
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
imap = imaplib.IMAP4(IMAP_HOST, IMAP_PORT)
imap.starttls(ctx)
imap.login(SMTP_USER, SMTP_PASS)
status, folders = imap.list()
folder_exists = any(DIGEST_FOLDER.encode() in f for f in (folders or []))
if not folder_exists:
imap.create(DIGEST_FOLDER)
log.info("Created IMAP folder: %s", DIGEST_FOLDER)
now = imaplib.Time2Internaldate(datetime.now(tz=ZoneInfo("UTC")))
imap.append(DIGEST_FOLDER, None, now, msg_bytes)
imap.logout()
log.info("Filed message to %s folder", DIGEST_FOLDER)
def send_email(subject: str, html_body: str = "", text_body: str = "",
to: str = DEFAULT_TO, from_addr: str = SMTP_USER):
"""Send email via Proton Bridge SMTP on localhost, then file into Digests folder."""
msg = MIMEMultipart("alternative")
msg["Subject"] = subject
msg["From"] = from_addr
msg["To"] = to
msg["Date"] = datetime.now(tz=ZoneInfo("America/Los_Angeles")).strftime(
"%a, %d %b %Y %H:%M:%S %z"
)
if text_body:
msg.attach(MIMEText(text_body, "plain"))
if html_body:
msg.attach(MIMEText(html_body, "html"))
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as server:
server.starttls(context=ctx)
server.login(SMTP_USER, SMTP_PASS)
server.send_message(msg)
log.info("Email sent: %s -> %s", subject, to)
try:
_file_to_digests(msg.as_bytes())
except Exception as e:
log.warning("Failed to file to Digests folder: %s", e)