Files
echo-core/tools/email_digest.py
Marius Mutu 30678e6abf fix(email): send WhatsApp notification when no new emails found
Previously digest and forward commands silently exited when inbox
was empty, leaving the user with no feedback after the initial
"processing..." confirmation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 20:29:58 +00:00

136 lines
3.9 KiB
Python

#!/usr/bin/env python3
"""
Email digest: procesează emailuri necitite și trimite rezumate pe WhatsApp.
Usage:
python3 tools/email_digest.py # Run digest
python3 tools/email_digest.py --dry-run # Afișează rezumatele fără a trimite
"""
import sys
import subprocess
import requests
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(PROJECT_ROOT))
from tools.email_process import save_unread_emails
from src.config import Config
BRIDGE_URL = "http://127.0.0.1:8098"
DRY_RUN = "--dry-run" in sys.argv
def get_owner_jid() -> str:
config = Config(PROJECT_ROOT / "config.json")
owner = config.get("whatsapp.owner", "")
return f"{owner}@s.whatsapp.net"
def generate_summary(filepath: str, subject: str, from_full: str, date: str) -> str:
"""Citește conținutul emailului și generează rezumat via Claude CLI."""
try:
email_content = Path(filepath).read_text(encoding="utf-8")
except Exception as e:
return f"[Eroare la citirea fișierului: {e}]"
prompt = f"""Mai jos este conținutul unui email. Generează un rezumat pentru WhatsApp.
EMAIL:
{email_content}
Format obligatoriu (plain text, fără markdown):
SUBIECT: {subject}
De la: {from_full}
Primit: {date}
---
[Rezumat compact dar complet — include TOATE detaliile importante:
- ce se întâmplă / despre ce e vorba
- cine organizează / cine trimite
- când (date, deadline-uri, perioade)
- unde (locație dacă există)
- ce trebuie să facă cititorul (acțiune clară)
- condiții de participare (vârstă, criterii etc.) dacă există
- ce este inclus/oferit dacă e relevant
Fiecare punct pe linie separată. Fără redundanță, fără filler.]
LINKURI:
[Listează TOATE linkurile acționabile: formulare, înscrieri, site-uri, documente, social media]
[Format: "Descriere scurtă: https://..." — câte un link per linie]
[Dacă nu există linkuri, omite secțiunea]
[Semnătura expeditorului din email pe ultima linie după —]
Fără emoji dacă nu sunt în original. Răspunde DOAR cu rezumatul, nimic altceva."""
result = subprocess.run(
["claude", "--print", prompt],
capture_output=True,
text=True,
timeout=60,
stdin=subprocess.DEVNULL,
)
if result.returncode != 0:
return f"[Eroare la generarea rezumatului pentru: {subject}]\n{result.stderr.strip()[:200]}"
return result.stdout.strip()
def send_whatsapp(to: str, text: str) -> bool:
"""Trimite mesaj pe WhatsApp prin bridge."""
try:
resp = requests.post(
f"{BRIDGE_URL}/send",
json={"to": to, "text": text},
timeout=15,
)
data = resp.json()
return data.get("ok", False)
except Exception as e:
print(f"[eroare send] {e}", file=sys.stderr)
return False
def run_digest():
print("📬 Verific emailuri necitite...")
saved = save_unread_emails()
owner_jid = get_owner_jid()
if not saved:
print("Niciun email nou de procesat.")
if not DRY_RUN:
send_whatsapp(owner_jid, "📭 Nu sunt emailuri noi.")
return
for result in saved:
if not result.get("ok"):
print(f"⚠️ Sărit: {result.get('error')}")
continue
filepath = result["file"]
subject = result["subject"]
from_full = result.get("from_full", result.get("from", ""))
date = result.get("date", "")
print(f"📧 Procesez: {subject}")
summary = generate_summary(filepath, subject, from_full, date)
if DRY_RUN:
print("\n--- REZUMAT (dry-run) ---")
print(summary)
print("------------------------\n")
else:
ok = send_whatsapp(owner_jid, summary)
if ok:
print(f"✅ Trimis pe WhatsApp: {subject}")
else:
print(f"❌ Trimitere eșuată: {subject}")
if __name__ == "__main__":
run_digest()