ligbox-ops-platform/projects/ops-desk/legacy-app/mail_notify.py
Ligbox Spec Hub 821675ab4a Reorganize monorepo into projects/wizard, ops-desk, finance
Specs stay at repo root (cross-VM). Move deploy and code into logical
projects with README per domain, updated manifest.yaml, and symlinks at
legacy paths for VM122 backward compatibility.
2026-06-19 18:55:03 +00:00

135 lines
4.5 KiB
Python

"""Send notification emails via Postfix (SMTP)."""
from __future__ import annotations
import os
import smtplib
from email.message import EmailMessage
ROOT_NOTIFY_EMAIL = os.getenv("DESK_ROOT_NOTIFY_EMAIL", "admin@ligbox.com.br")
DESK_PUBLIC_URL = os.getenv("DESK_PUBLIC_URL", "https://desk.ligbox.com.br")
MAIL_FROM = os.getenv("DESK_MAIL_FROM", "ligbox-ops@ligbox.com.br")
SMTP_HOST = os.getenv("DESK_SMTP_HOST", "10.10.10.122")
SMTP_PORT = int(os.getenv("DESK_SMTP_PORT", "25"))
def send_email(to: str, subject: str, body: str) -> bool:
to = (to or "").strip()
if not to:
return False
msg = EmailMessage()
msg["From"] = MAIL_FROM
msg["To"] = to
msg["Subject"] = subject
msg.set_content(body)
try:
with smtplib.SMTP(SMTP_HOST, SMTP_PORT, timeout=15) as smtp:
smtp.send_message(msg)
return True
except Exception:
return False
def notify_root_registration_pending(email: str, request_id: int) -> bool:
body = (
f"Novo pedido de cadastro Ligbox Ops Desk\n\n"
f"E-mail: {email}\n"
f"ID: {request_id}\n\n"
f"Aprovar em: {DESK_PUBLIC_URL}/\n"
f"(Menu Mensagens)\n"
)
return send_email(ROOT_NOTIFY_EMAIL, f"[Ligbox Ops] Pedido de cadastro: {email}", body)
def notify_candidate_approved(email: str, activation_url: str, role: str) -> bool:
body = (
f"Seu pedido de acesso ao Ligbox Ops Desk foi APROVADO.\n\n"
f"Perfil atribuído: {role}\n\n"
f"Ative sua conta (complete 2 de 3 fatores: e-mail, telefone ou app 2FA):\n{activation_url}\n\n"
f"Este link expira em 48 horas.\n"
)
return send_email(email, "[Ligbox Ops] Conta aprovada — ative agora", body)
def notify_candidate_rejected(email: str, reason: str | None = None) -> bool:
body = "Seu pedido de acesso ao Ligbox Ops Desk foi rejeitado."
if reason:
body += f"\n\nMotivo: {reason}"
return send_email(email, "[Ligbox Ops] Pedido de cadastro rejeitado", body)
def send_otp_email(email: str, code: str, purpose: str) -> bool:
body = (
f"Código de verificação Ligbox Ops Desk\n\n"
f"Finalidade: {purpose}\n"
f"Código: {code}\n\n"
f"Válido por 10 minutos.\n"
)
return send_email(email, f"[Ligbox Ops] Código: {code}", body)
def mask_email(email: str) -> str:
email = (email or "").strip()
if "@" not in email:
return email
local, domain = email.split("@", 1)
if len(local) <= 2:
masked_local = local[0] + "***"
else:
masked_local = local[0] + "***" + local[-1]
return f"{masked_local}@{domain}"
def notify_mfa_recovery_started(username: str, email: str) -> bool:
body = (
f"Recuperação de 2FA iniciada no Ligbox Ops Desk\n\n"
f"Utilizador: {username}\n"
f"E-mail de verificação: {email}\n\n"
f"Se não foi você, contacte o root imediatamente.\n"
)
return send_email(
ROOT_NOTIFY_EMAIL,
f"[Ligbox Ops] Recuperação 2FA: {username}",
body,
)
def notify_mfa_recovery_completed(username: str) -> bool:
body = (
f"Recuperação de 2FA concluída no Ligbox Ops Desk\n\n"
f"Utilizador: {username}\n"
f"Novo autenticador configurado e códigos de backup gerados.\n"
)
return send_email(
ROOT_NOTIFY_EMAIL,
f"[Ligbox Ops] 2FA reconfigurado: {username}",
body,
)
def notify_admin_2fa_reset(target_username: str, target_email: str, admin_username: str) -> bool:
body = (
f"O administrador {admin_username} resetou o 2FA da conta:\n\n"
f"Utilizador: {target_username}\n"
f"E-mail: {target_email}\n\n"
f"O utilizador pode entrar só com senha e reconfigurar o autenticador em:\n"
f"{DESK_PUBLIC_URL}/login.html\n"
f"(Perdi acesso ao autenticador)\n"
)
send_email(target_email, "[Ligbox Ops] 2FA resetado pelo administrador", body)
return send_email(
ROOT_NOTIFY_EMAIL,
f"[Ligbox Ops] Admin resetou 2FA: {target_username}",
body,
)
def send_backup_codes_email(email: str, codes: list[str]) -> bool:
lines = "\n".join(f"{c}" for c in codes)
body = (
f"Códigos de backup — Ligbox Ops Desk\n\n"
f"Guarde estes códigos em local seguro. Cada código só pode ser usado uma vez.\n\n"
f"{lines}\n\n"
f"Use-os no login se perder acesso ao aplicativo autenticador.\n"
)
return send_email(email, "[Ligbox Ops] Códigos de backup 2FA", body)