184 lines
6.9 KiB
Python
Executable File
184 lines
6.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Serveur SMTP de débogage pour Notytex
|
|
======================================
|
|
|
|
Serveur SMTP de développement qui affiche les emails en console au lieu de les envoyer.
|
|
Idéal pour tester l'envoi de bilans sans configuration SMTP réelle.
|
|
|
|
Usage:
|
|
python debug_smtp_server.py
|
|
|
|
Configuration dans l'interface web:
|
|
- Serveur SMTP: localhost
|
|
- Port: 1025
|
|
- Utilisateur/Mot de passe: (laisser vides)
|
|
- TLS: Désactivé
|
|
"""
|
|
|
|
import asyncio
|
|
import email
|
|
from email.policy import default
|
|
from datetime import datetime
|
|
from aiosmtpd.controller import Controller
|
|
from aiosmtpd.smtp import SMTP as SMTPServer
|
|
|
|
|
|
class DebugSMTPHandler:
|
|
"""Gestionnaire personnalisé pour afficher les emails en console."""
|
|
|
|
async def handle_DATA(self, server, session, envelope):
|
|
"""
|
|
Traite les emails reçus et les affiche en console.
|
|
|
|
Args:
|
|
server: Instance du serveur SMTP
|
|
session: Session SMTP courante
|
|
envelope: Envelope contenant les données de l'email
|
|
|
|
Returns:
|
|
str: Code de statut SMTP
|
|
"""
|
|
print("\n" + "=" * 80)
|
|
print("📧 NOUVEL EMAIL REÇU")
|
|
print("=" * 80)
|
|
|
|
# Informations de l'envelope
|
|
print(f"\n🔹 De: {envelope.mail_from}")
|
|
print(f"🔹 À: {', '.join(envelope.rcpt_tos)}")
|
|
print(f"🔹 Timestamp: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
|
|
# Parse le contenu de l'email
|
|
try:
|
|
msg = email.message_from_bytes(envelope.content, policy=default)
|
|
|
|
# En-têtes principaux
|
|
print(f"\n📋 HEADERS:")
|
|
print(f" Subject: {msg.get('Subject', '(sans sujet)')}")
|
|
print(f" From: {msg.get('From', '(inconnu)')}")
|
|
print(f" To: {msg.get('To', '(inconnu)')}")
|
|
print(f" Date: {msg.get('Date', '(inconnue)')}")
|
|
|
|
# Parcourir les parties du message
|
|
if msg.is_multipart():
|
|
print(f"\n📦 MESSAGE MULTIPART ({len(msg.get_payload())} parties)")
|
|
|
|
for idx, part in enumerate(msg.iter_parts(), 1):
|
|
content_type = part.get_content_type()
|
|
print(f"\n Partie {idx}: {content_type}")
|
|
|
|
# Afficher le contenu texte
|
|
if content_type == 'text/plain':
|
|
text_content = part.get_content()
|
|
print(f"\n 📄 CONTENU TEXTE:")
|
|
print(" " + "-" * 76)
|
|
for line in text_content.split('\n')[:20]: # Limiter à 20 lignes
|
|
print(f" {line}")
|
|
if len(text_content.split('\n')) > 20:
|
|
print(f" ... ({len(text_content.split('\n')) - 20} lignes supplémentaires)")
|
|
print(" " + "-" * 76)
|
|
|
|
# Afficher un aperçu du contenu HTML
|
|
elif content_type == 'text/html':
|
|
html_content = part.get_content()
|
|
print(f"\n 🎨 CONTENU HTML ({len(html_content)} caractères)")
|
|
print(" " + "-" * 76)
|
|
|
|
# Extraire et afficher le titre si présent
|
|
if '<title>' in html_content:
|
|
import re
|
|
title_match = re.search(r'<title>(.*?)</title>', html_content, re.IGNORECASE)
|
|
if title_match:
|
|
print(f" Titre: {title_match.group(1)}")
|
|
|
|
# Afficher un extrait du HTML
|
|
lines = html_content.split('\n')
|
|
preview_lines = [l.strip() for l in lines if l.strip() and not l.strip().startswith('<!')][:10]
|
|
for line in preview_lines:
|
|
print(f" {line[:100]}")
|
|
|
|
print(f" ... (aperçu du HTML)")
|
|
print(" " + "-" * 76)
|
|
|
|
# Sauvegarder le HTML pour consultation
|
|
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
|
filename = f"debug_email_{timestamp}.html"
|
|
try:
|
|
with open(filename, 'w', encoding='utf-8') as f:
|
|
f.write(html_content)
|
|
print(f"\n 💾 HTML sauvegardé dans: {filename}")
|
|
except Exception as e:
|
|
print(f"\n ⚠️ Erreur sauvegarde HTML: {e}")
|
|
|
|
else:
|
|
# Message simple (non multipart)
|
|
content = msg.get_content()
|
|
print(f"\n📄 CONTENU:")
|
|
print("-" * 80)
|
|
print(content[:1000]) # Limiter à 1000 caractères
|
|
if len(content) > 1000:
|
|
print(f"... ({len(content) - 1000} caractères supplémentaires)")
|
|
print("-" * 80)
|
|
|
|
except Exception as e:
|
|
print(f"\n❌ ERREUR lors du parsing de l'email: {e}")
|
|
print("\n📋 CONTENU BRUT:")
|
|
print("-" * 80)
|
|
print(envelope.content.decode('utf-8', errors='replace')[:2000])
|
|
print("-" * 80)
|
|
|
|
print("\n" + "=" * 80)
|
|
print("✅ Email traité avec succès")
|
|
print("=" * 80 + "\n")
|
|
|
|
return '250 Message accepted for delivery'
|
|
|
|
|
|
async def run_server():
|
|
"""Lance le serveur SMTP et attend indéfiniment."""
|
|
handler = DebugSMTPHandler()
|
|
controller = Controller(handler, hostname='localhost', port=1025)
|
|
|
|
controller.start()
|
|
print("✅ Serveur démarré avec succès!")
|
|
print("📬 En attente d'emails... (Ctrl+C pour arrêter)\n")
|
|
|
|
try:
|
|
# Attendre indéfiniment
|
|
while True:
|
|
await asyncio.sleep(3600)
|
|
finally:
|
|
controller.stop()
|
|
|
|
|
|
def main():
|
|
"""Lance le serveur SMTP de débogage."""
|
|
|
|
print("\n" + "=" * 80)
|
|
print("🚀 SERVEUR SMTP DE DÉBOGAGE NOTYTEX")
|
|
print("=" * 80)
|
|
print("\nConfiguration recommandée dans l'interface web:")
|
|
print(" • Serveur SMTP: localhost")
|
|
print(" • Port: 1025")
|
|
print(" • Utilisateur: (laisser vide)")
|
|
print(" • Mot de passe: (laisser vide)")
|
|
print(" • TLS: Désactivé")
|
|
print("\n" + "-" * 80)
|
|
print("📡 Démarrage du serveur sur localhost:1025...")
|
|
print("-" * 80 + "\n")
|
|
|
|
try:
|
|
asyncio.run(run_server())
|
|
except KeyboardInterrupt:
|
|
print("\n\n" + "=" * 80)
|
|
print("🛑 Arrêt du serveur...")
|
|
print("=" * 80)
|
|
print("✅ Serveur arrêté proprement\n")
|
|
except Exception as e:
|
|
print(f"\n❌ ERREUR: {e}")
|
|
raise
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|