Files
echo-core/tools/email_digest.py
Marius Mutu 417de65069 fix(email): use original sender for forwarded emails in digest
Digest was attributing forwarded emails to the person who forwarded
them. Now Claude is instructed to identify the original sender from
the forwarded headers and ignore the forwarder entirely. Also drops
pleasantries/apologies from the summary — facts only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 07:48:11 +00:00

131 lines
4.2 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. Scrie un rezumat factual pentru WhatsApp.
EMAIL:
{email_content}
Instrucțiuni:
- Începe cu header-ul fix (fără modificări):
SUBIECT: {subject}
De la: {from_full}
Primit: {date}
---
- Dacă emailul este un forward (subiect începe cu Fwd:/Fw: sau conține "---------- Forwarded message"):
* Ignoră complet persoana care a forwardat. Nu o menționez în rezumat.
* Identifică expeditorul original din corpul emailului (câmpurile From/De la din headerul forwarded).
* Rezumatul trebuie să fie despre mesajul original, ca și cum ar fi fost primit direct de la acel expeditor.
- Scrie rezumatul în stil briefing: factual, clar, persoana a 3-a.
* Prima propoziție: cine a trimis mesajul original, ce, cui.
* Ce conține mesajul — concret și direct. Omite politețuri, scuze și amabilități; include doar faptele.
* Dacă există termene, date, locuri sau acțiuni cerute — menționează-le explicit.
* Dacă există atașamente — listează-le la final: "Atașat: ..."
* Dacă există linkuri acționabile (formulare, documente), adaugă o secțiune LINKURI la final.
- Nu adăuga secțiuni goale sau care nu se aplică emailului.
- Plain text, fără markdown. Fără emoji.
- 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()