From 85f32c35bb00a1c98c6072ee453ecfb72503e721 Mon Sep 17 00:00:00 2001 From: Jules Date: Mon, 22 Jun 2026 19:42:25 +0200 Subject: [PATCH] Rapport email a contact@copydev.fr apres vidage du spool Au demarrage, si le spool contient des emails en attente, les envoie puis envoie un rapport recapitulatif (nb envoyes + liste destinataires) Co-Authored-By: Claude Opus 4.6 --- backend/mailer.py | 66 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/backend/mailer.py b/backend/mailer.py index 3608a13..695b5ba 100644 --- a/backend/mailer.py +++ b/backend/mailer.py @@ -104,14 +104,18 @@ def taille_spool() -> int: return len(_charger_spool()) -def traiter_spool() -> int: - """Tente d'envoyer les emails en attente. Retourne le nombre envoyes.""" +EMAIL_RAPPORT = "contact@copydev.fr" + + +def traiter_spool() -> tuple[int, list[str]]: + """Tente d'envoyer les emails en attente. Retourne (nb envoyes, liste destinataires).""" with _spool_lock: spool = _charger_spool() if not spool: - return 0 + return 0, [] envoyes = 0 + destinataires = [] restants = [] for entry in spool: chemin = Path(entry["photo"]) @@ -121,27 +125,71 @@ def traiter_spool() -> int: ok = envoyer_photo(entry["email"], chemin) if ok: envoyes += 1 + destinataires.append(entry["email"]) else: restants.append(entry) - break # si un echoue, inutile de continuer (pas de connexion) + break if envoyes > 0 or len(restants) < len(spool): - # garder les non-envoyes + ceux pas encore tentes idx = envoyes + len(restants) restants.extend(spool[idx:]) with _spool_lock: _sauver_spool(restants) log.info(f"Spool: {envoyes} envoye(s), {len(restants)} en attente") - return envoyes + return envoyes, destinataires + + +def envoyer_rapport_spool(nb_envoyes: int, destinataires: list[str], nb_echoues: int): + """Envoie un rapport a contact@copydev.fr apres vidage du spool.""" + config = charger_config() + conf_email = config.get("email", {}) + conf_event = config.get("evenement", {}) + nom_event = conf_event.get("nom", "Photobooth") + + smtp_host = conf_email.get("smtp_host", "") + smtp_port = conf_email.get("smtp_port", 587) + smtp_user = conf_email.get("smtp_user", "") + smtp_password = conf_email.get("smtp_password", "") + expediteur = conf_email.get("expediteur", smtp_user) + + if not smtp_host or not smtp_user: + return + + liste = "\n".join(f" - {d}" for d in destinataires) + corps = f"{nb_envoyes} photo(s) envoyée(s) par email.\n\n" + corps += f"Destinataires :\n{liste}\n" + if nb_echoues > 0: + corps += f"\n{nb_echoues} email(s) en échec (restent en file d'attente).\n" + + msg = MIMEMultipart() + msg["From"] = expediteur + msg["To"] = EMAIL_RAPPORT + msg["Subject"] = f"[{nom_event}] {nb_envoyes} photo(s) envoyée(s)" + msg.attach(MIMEText(corps, "plain", "utf-8")) + + try: + with smtplib.SMTP(smtp_host, smtp_port, timeout=10) as serveur: + serveur.starttls() + serveur.login(smtp_user, smtp_password) + serveur.send_message(msg) + log.info(f"Rapport spool envoye a {EMAIL_RAPPORT}") + except (smtplib.SMTPException, OSError) as e: + log.error(f"Erreur envoi rapport spool : {e}") async def tache_spool_demarrage(): """Tente de vider le spool une seule fois au demarrage du serveur.""" await asyncio.sleep(10) - if taille_spool() > 0: - log.info(f"Spool: tentative d'envoi au demarrage ({taille_spool()} en attente)") - await asyncio.get_event_loop().run_in_executor(None, traiter_spool) + total = taille_spool() + if total > 0: + log.info(f"Spool: tentative d'envoi au demarrage ({total} en attente)") + nb, dests = await asyncio.get_event_loop().run_in_executor(None, traiter_spool) + if nb > 0: + echoues = total - nb + await asyncio.get_event_loop().run_in_executor( + None, envoyer_rapport_spool, nb, dests, echoues + ) FICHIER_EMAILS = RACINE / "data" / "emails_history.json"