All checks were successful
Deploy / deploy (push) Successful in 25s
Phoenix doesn't observe DST, so schedule times stay meaningful year-round without needing a seasonal adjustment. notify.py reuses lunch-notifier's existing Gmail-SMTP-with-app-password pattern rather than adding a new notification channel. The alert fires exactly once per expiry (not on every failed scheduled run while it's down) via a dedupe flag in notify_state.json, reset the moment a fresh session is successfully imported. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H6TgffxTvYhqxykAbVQg2v
34 lines
1.2 KiB
Python
34 lines
1.2 KiB
Python
"""Email alerts via Gmail SMTP + app password — the same pattern already
|
|
used by lunch-notifier on this box, reused here rather than adding a new
|
|
notification service. Silently a no-op if GMAIL_USER/GMAIL_APP_PASSWORD
|
|
aren't set, so the alert feature is opt-in.
|
|
"""
|
|
import logging
|
|
import os
|
|
import smtplib
|
|
from email.mime.text import MIMEText
|
|
|
|
logger = logging.getLogger("massprice.notify")
|
|
|
|
GMAIL_USER = os.environ.get("GMAIL_USER")
|
|
GMAIL_APP_PASSWORD = os.environ.get("GMAIL_APP_PASSWORD")
|
|
ALERT_EMAIL = os.environ.get("ALERT_EMAIL") or GMAIL_USER
|
|
|
|
|
|
def send_alert(subject, body):
|
|
"""Best-effort: logs and returns False on any failure rather than
|
|
raising, since a broken alert channel shouldn't break automation."""
|
|
if not GMAIL_USER or not GMAIL_APP_PASSWORD or not ALERT_EMAIL:
|
|
return False
|
|
msg = MIMEText(body)
|
|
msg["Subject"] = subject
|
|
msg["From"] = GMAIL_USER
|
|
msg["To"] = ALERT_EMAIL
|
|
try:
|
|
with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
|
|
server.login(GMAIL_USER, GMAIL_APP_PASSWORD)
|
|
server.sendmail(GMAIL_USER, [ALERT_EMAIL], msg.as_string())
|
|
return True
|
|
except Exception:
|
|
logger.exception("Failed to send alert email")
|
|
return False
|