From eecd8e24e5f29e6845a610bae634a55cebba6b1c Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 21 Jun 2026 14:18:24 +0000 Subject: [PATCH] Add email SMTP diagnostic script for docker logs --- tools/email_diagnostics.py | 125 +++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 tools/email_diagnostics.py diff --git a/tools/email_diagnostics.py b/tools/email_diagnostics.py new file mode 100644 index 0000000..e35c170 --- /dev/null +++ b/tools/email_diagnostics.py @@ -0,0 +1,125 @@ +""" +Diagnostic script for ScrAIbe email (SMTP) connectivity. + +Run inside the container to verify: +- Required env vars are set +- SMTP connection +- TLS (if configured) +- Authentication + +Output is written to stdout/stderr so it appears in docker logs. +""" + +import os +import sys +import smtplib +import logging + +logging.basicConfig( + level=logging.INFO, + format="DIAG [%(levelname)s] %(message)s", + stream=sys.stdout, + force=True, +) +log = logging.getLogger("email_diagnostics") + + +def main(): + # 1) Check required env vars + required = [ + "EMAIL_SMTP_HOST", + "EMAIL_SMTP_PORT", + "EMAIL_SMTP_USER", + "EMAIL_SMTP_PASSWORD", + "EMAIL_FROM_ADDRESS", + ] + missing = [v for v in required if not os.getenv(v)] + if missing: + log.error("Missing required env vars: %s", ", ".join(missing)) + sys.exit(1) + + smtp_host = os.getenv("EMAIL_SMTP_HOST") + smtp_port = int(os.getenv("EMAIL_SMTP_PORT")) + smtp_user = os.getenv("EMAIL_SMTP_USER") + smtp_password = os.getenv("EMAIL_SMTP_PASSWORD") + from_address = os.getenv("EMAIL_FROM_ADDRESS") + use_tls_str = (os.getenv("EMAIL_SMTP_USE_TLS") or "true").strip().lower() + use_tls = use_tls_str not in ("false", "0", "no") + + log.info("SMTP config:") + log.info(" host: %s", smtp_host) + log.info(" port: %s", smtp_port) + log.info(" user: %s", smtp_user) + log.info(" from: %s", from_address) + log.info(" use_tls: %s", use_tls) + log.info(" password: %s", ("set" if smtp_password else "NOT SET")) + + # 2) Connect to SMTP server + log.info("Attempting SMTP connection...") + try: + if use_tls: + server = smtplib.SMTP(smtp_host, smtp_port, timeout=15) + log.info("Connected (SMTP) to %s:%s", smtp_host, smtp_port) + else: + server = smtplib.SMTP(smtp_host, smtp_port, timeout=15) + log.info("Connected (SMTP, no TLS) to %s:%s", smtp_host, smtp_port) + except Exception as e: + log.error("SMTP connection failed: %s", e) + sys.exit(1) + + # 3) EHLO + log.info("Sending EHLO...") + try: + ehlo_resp = server.ehlo() + log.info("EHLO response code: %s", ehlo_resp[0]) + except Exception as e: + log.error("EHLO failed: %s", e) + server.quit() + sys.exit(1) + + # 4) STARTTLS if configured + if use_tls: + log.info("Attempting STARTTLS...") + try: + server.starttls() + server.ehlo() + log.info("STARTTLS succeeded.") + except Exception as e: + log.error("STARTTLS failed: %s", e) + server.quit() + sys.exit(1) + else: + log.info("TLS not requested; continuing without STARTTLS.") + + # 5) AUTH LOGIN + log.info("Attempting AUTH LOGIN with user: %s", smtp_user) + try: + server.login(smtp_user, smtp_password) + log.info("AUTH LOGIN succeeded.") + except smtplib.SMTPAuthenticationError as e: + log.error("AUTH LOGIN failed (bad credentials?): %s", e) + server.quit() + sys.exit(1) + except Exception as e: + log.error("AUTH LOGIN failed: %s", e) + server.quit() + sys.exit(1) + + # 6) Optional: quick MAIL FROM / RCPT TO / QUIT test (no message sent) + log.info("Testing MAIL FROM / RCPT TO / RSET...") + try: + server.mail(from_address) + # Use from_address as recipient for test + server.rcpt(from_address) + server.reset() + log.info("MAIL FROM / RCPT TO / RSET succeeded.") + except Exception as e: + log.warning("MAIL FROM / RCPT TO / RSET failed (non-critical): %s", e) + + # 7) Quit + server.quit() + log.info("All email diagnostics passed. SMTP is reachable and authenticated.") + + +if __name__ == "__main__": + main()