215 lines
7.5 KiB
Python
Executable file
215 lines
7.5 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""
|
|
Script pour la création de brouillons d'e-mails pour Outlook (PWA / Web sous Ubuntu).
|
|
|
|
Consomme le fichier 'drafts_payload.json' (ou le dossier généré lors de la création d'utilisateurs).
|
|
Modes disponibles :
|
|
- pwa (défaut) : Ouvre directement les deep links de composition dans Chromium avec la session Outlook connectée.
|
|
- html : Ouvre la page web interactive locale 'open_drafts.html'.
|
|
- eml : Exporte des fichiers brouillons standards .eml (RFC822 avec X-Unsent: 1).
|
|
|
|
Usage :
|
|
python scripts/create_outlook_drafts.py chemin/vers/drafts_payload.json
|
|
python scripts/create_outlook_drafts.py chemin/vers/drafts_payload.json --step
|
|
python scripts/create_outlook_drafts.py chemin/vers/drafts_payload.json --delay 3
|
|
python scripts/create_outlook_drafts.py chemin/vers/drafts_payload.json --mode html
|
|
python scripts/create_outlook_drafts.py chemin/vers/drafts_payload.json --mode eml
|
|
"""
|
|
|
|
import argparse
|
|
import email.message
|
|
import json
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import urllib.parse
|
|
import webbrowser
|
|
from pathlib import Path
|
|
|
|
|
|
def find_chromium_cmd() -> list:
|
|
"""Détecte la commande Chromium disponible pour ouvrir la session PWA sous Ubuntu."""
|
|
candidates = [
|
|
"/snap/bin/chromium",
|
|
"chromium",
|
|
"chromium-browser",
|
|
"google-chrome",
|
|
"google-chrome-stable",
|
|
]
|
|
for cmd in candidates:
|
|
if shutil.which(cmd):
|
|
# Vérifier si on peut ajouter le profil Default
|
|
return [cmd, "--profile-directory=Default"]
|
|
return []
|
|
|
|
|
|
def create_eml_draft(to_email: str, subject: str, body: str, output_path: Path):
|
|
"""Génère un fichier .eml standard marqué comme brouillon (X-Unsent: 1)."""
|
|
msg = email.message.EmailMessage()
|
|
msg["To"] = to_email
|
|
msg["Subject"] = subject
|
|
msg["X-Unsent"] = "1" # Marqueur standard de brouillon pour Outlook, Thunderbird, Apple Mail
|
|
msg.set_content(body)
|
|
|
|
with open(output_path, "wb") as f:
|
|
f.write(msg.as_bytes())
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Crée des brouillons d'e-mails dans Outlook PWA / Web ou génère des fichiers brouillons."
|
|
)
|
|
parser.add_argument(
|
|
"input",
|
|
type=str,
|
|
help="Chemin vers le fichier drafts_payload.json ou le dossier de sortie de création d'utilisateurs.",
|
|
)
|
|
parser.add_argument(
|
|
"--mode",
|
|
choices=["pwa", "html", "eml"],
|
|
default="pwa",
|
|
help="Mode de traitement : 'pwa' (ouvre dans Outlook PWA), 'html' (ouvre la page locale), 'eml' (exporte des fichiers .eml).",
|
|
)
|
|
parser.add_argument(
|
|
"--delay",
|
|
type=float,
|
|
default=2.5,
|
|
help="Délai en secondes entre l'ouverture de chaque brouillon en mode automatique (défaut : 2.5s).",
|
|
)
|
|
parser.add_argument(
|
|
"--step",
|
|
action="store_true",
|
|
default=False,
|
|
help="Mode pas-à-pas : demande confirmation avant d'ouvrir chaque brouillon.",
|
|
)
|
|
parser.add_argument(
|
|
"--dry-run",
|
|
action="store_true",
|
|
default=False,
|
|
help="Affiche les actions prévues sans ouvrir de navigateur ni créer de fichiers.",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
input_path = Path(args.input)
|
|
if not input_path.exists():
|
|
sys.stderr.write(f"Erreur : '{args.input}' est introuvable.\n")
|
|
sys.exit(1)
|
|
|
|
# Résoudre le fichier drafts_payload.json
|
|
payload_file = input_path
|
|
if input_path.is_dir():
|
|
payload_file = input_path / "drafts_payload.json"
|
|
if not payload_file.exists():
|
|
sys.stderr.write(f"Erreur : Aucun fichier drafts_payload.json trouvé dans '{input_path}'.\n")
|
|
sys.exit(1)
|
|
|
|
try:
|
|
with open(payload_file, "r", encoding="utf-8") as f:
|
|
drafts = json.load(f)
|
|
except Exception as exc:
|
|
sys.stderr.write(f"Erreur lors de la lecture de {payload_file} : {exc}\n")
|
|
sys.exit(1)
|
|
|
|
if not isinstance(drafts, list) or not drafts:
|
|
print("Aucun brouillon trouvé dans la charge utile.")
|
|
return
|
|
|
|
print(f"Chargement de {len(drafts)} brouillon(s) depuis {payload_file.name}...")
|
|
|
|
# Mode HTML
|
|
if args.mode == "html":
|
|
html_file = payload_file.parent / "open_drafts.html"
|
|
if not html_file.exists():
|
|
sys.stderr.write(f"Page HTML introuvable à {html_file}.\n")
|
|
sys.exit(1)
|
|
print(f"Ouverture de la page interactive : {html_file.resolve()}")
|
|
if not args.dry_run:
|
|
webbrowser.open(f"file://{html_file.resolve()}")
|
|
return
|
|
|
|
# Mode EML
|
|
if args.mode == "eml":
|
|
eml_dir = payload_file.parent / "eml_drafts"
|
|
if not args.dry_run:
|
|
eml_dir.mkdir(parents=True, exist_ok=True)
|
|
print(f"Génération des fichiers .eml dans {eml_dir.resolve()}...")
|
|
for item in drafts:
|
|
username = item.get("username", "user")
|
|
out_eml = eml_dir / f"{username}_draft.eml"
|
|
print(f" -> {out_eml.name} ({item.get('to')})")
|
|
if not args.dry_run:
|
|
create_eml_draft(
|
|
to_email=item.get("to", ""),
|
|
subject=item.get("subject", ""),
|
|
body=item.get("body", ""),
|
|
output_path=out_eml,
|
|
)
|
|
print("Fichiers .eml générés avec succès.")
|
|
return
|
|
|
|
# Mode PWA (Défaut)
|
|
chromium_cmd = find_chromium_cmd()
|
|
if chromium_cmd:
|
|
print(f"Navigateur détecté pour la session PWA : {' '.join(chromium_cmd)}")
|
|
else:
|
|
print("Utilisation du navigateur système par défaut.")
|
|
|
|
print("\n" + "=" * 60)
|
|
print(f"Ouverture des brouillons dans Outlook ({len(drafts)} message(s))")
|
|
print("Outlook sauvegardera automatiquement chaque message dans le dossier 'Brouillons'.")
|
|
print("=" * 60 + "\n")
|
|
|
|
for idx, item in enumerate(drafts, start=1):
|
|
to_email = item.get("to", "")
|
|
subject = item.get("subject", "")
|
|
deeplink = item.get("outlook_deeplink")
|
|
first_name = item.get("first_name", "")
|
|
last_name = item.get("last_name", "")
|
|
|
|
if not deeplink:
|
|
params = urllib.parse.urlencode({
|
|
"to": to_email,
|
|
"subject": subject,
|
|
"body": item.get("body", ""),
|
|
})
|
|
deeplink = f"https://outlook.cloud.microsoft/mail/deeplink/compose?{params}"
|
|
|
|
print(f"[{idx}/{len(drafts)}] {first_name} {last_name} <{to_email}>")
|
|
|
|
if args.step:
|
|
choice = input(" -> Appuyez sur Entrée pour ouvrir dans Outlook (ou 'q' pour quitter, 's' pour passer) : ").strip().lower()
|
|
if choice == "q":
|
|
print("Arrêt demandé par l'utilisateur.")
|
|
break
|
|
elif choice == "s":
|
|
print(" Passé.")
|
|
continue
|
|
|
|
if args.dry_run:
|
|
print(f" [DRY-RUN] Ouverture de : {deeplink[:90]}...")
|
|
else:
|
|
if chromium_cmd:
|
|
try:
|
|
subprocess.Popen(
|
|
chromium_cmd + [deeplink],
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
)
|
|
except Exception:
|
|
webbrowser.open(deeplink)
|
|
else:
|
|
webbrowser.open(deeplink)
|
|
|
|
print(" -> Brouillon ouvert dans Outlook !")
|
|
|
|
if not args.step and idx < len(drafts) and not args.dry_run:
|
|
time.sleep(args.delay)
|
|
|
|
print("\nTous les brouillons ont été traités.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|