# Guide d'ouverture des fichiers .mbox de Google Takeout Ce guide explique comment ouvrir et exploiter un fichier .mbox exporté par Google Takeout. ## 1. Qu'est-ce qu'un fichier .mbox Le format **mbox** (mailbox) est un format standard pour stocker des collections d'emails. Google Takeout exporte les emails Gmail dans ce format. ### Structure du fichier : - **Un seul fichier** contenant tous les emails - **Format texte** avec séparateurs spéciaux - **Headers et corps** des emails en texte brut - **Pièces jointes** encodées en base64 ### ⚠️ Limitations importantes concernant l'arborescence : #### Ce qui est préservé : - ✅ **Contenu des emails** (headers, corps, pièces jointes) - ✅ **Métadonnées** (expéditeur, destinataire, date, sujet) - ✅ **Labels Gmail** (dans les headers comme `X-Gmail-Labels`) - ✅ **Conversations** (via `Message-ID` et `In-Reply-To`) #### Ce qui est perdu : - ❌ **Structure des dossiers Gmail** (hiérarchie) - ❌ **Organisation en dossiers** telle qu'elle apparaît dans Gmail - ❌ **Statuts des messages** (lu/non-lu, important, etc.) - ❌ **Tri chronologique** exact des conversations **Important** : Gmail utilise un système de **labels** plutôt que de vrais dossiers. Dans le .mbox, ces labels apparaissent comme : ``` X-Gmail-Labels: Important,Work,Project-Alpha ``` Ces labels sont inclus mais **pas l'arborescence visuelle** de Gmail. ## 2. Méthodes d'ouverture ### Méthode 1 : Thunderbird (Recommandée) #### Import direct : 1. **Ouvrir Thunderbird** 2. **Outils** → **Importer** → **Importer à partir d'un fichier** 3. Sélectionner **"Fichier mbox"** 4. Choisir le fichier `.mbox` de Google Takeout 5. Sélectionner le dossier de destination #### Avec ImportExportTools NG : ```bash # Installer l'extension ImportExportTools NG d'abord ``` 1. **Clic droit** sur un dossier dans Thunderbird 2. **ImportExportTools NG** → **Importer fichier mbox** 3. Sélectionner le fichier `.mbox` 4. Les emails apparaissent dans le dossier choisi ### Méthode 2 : Apple Mail (macOS) 1. **Ouvrir Apple Mail** 2. **Fichier** → **Importer des boîtes aux lettres** 3. Sélectionner **"Fichiers au format mbox"** 4. Choisir le fichier et importer ### Méthode 3 : Outils en ligne de commande #### Avec Python et mailbox : ```python #!/usr/bin/env python3 import mailbox import email from email.header import decode_header def read_mbox(mbox_path): """ Lire et afficher les emails d'un fichier mbox """ mbox = mailbox.mbox(mbox_path) for i, message in enumerate(mbox): print(f"\n=== Email {i+1} ===") # Décoder l'objet subject = decode_header(message['Subject'])[0][0] if isinstance(subject, bytes): subject = subject.decode('utf-8') print(f"Sujet: {subject}") # Expéditeur et destinataire print(f"De: {message['From']}") print(f"À: {message['To']}") print(f"Date: {message['Date']}") # Corps du message if message.is_multipart(): for part in message.walk(): if part.get_content_type() == "text/plain": body = part.get_payload(decode=True) if body: print(f"Corps: {body.decode('utf-8', errors='ignore')[:200]}...") else: body = message.get_payload(decode=True) if body: print(f"Corps: {body.decode('utf-8', errors='ignore')[:200]}...") # Utilisation read_mbox('/path/to/gmail.mbox') ``` #### Avec mutt (Linux) : ```bash # Installer mutt sudo apt install mutt # Ouvrir le fichier mbox mutt -f /path/to/gmail.mbox ``` ### Méthode 4 : Outils graphiques #### MailStore Home (Windows - Gratuit) : 1. Télécharger MailStore Home 2. **Archiver** → **Email** → **Fichiers Email** 3. Sélectionner le format **"Unix Mailbox (mbox)"** 4. Choisir le fichier et importer #### Evolution (Linux) : 1. **Fichier** → **Importer** 2. Sélectionner **"Importer un seul fichier"** 3. Choisir le fichier `.mbox` ## 3. Conversion vers d'autres formats ### Vers PST (Outlook) : ```python #!/usr/bin/env python3 import mailbox import os def mbox_to_eml(mbox_path, output_dir): """ Convertir mbox vers fichiers EML individuels """ if not os.path.exists(output_dir): os.makedirs(output_dir) mbox = mailbox.mbox(mbox_path) for i, message in enumerate(mbox): # Créer un nom de fichier basé sur l'objet subject = message.get('Subject', f'Email_{i}') # Nettoyer le nom de fichier filename = "".join(c for c in subject if c.isalnum() or c in (' ', '-', '_')).rstrip() filename = f"{i:04d}_{filename[:50]}.eml" # Écrire le fichier EML with open(os.path.join(output_dir, filename), 'w', encoding='utf-8') as f: f.write(str(message)) print(f"Exporté: {filename}") # Utilisation mbox_to_eml('/path/to/gmail.mbox', '/path/to/eml_output/') ``` ### Vers CSV (métadonnées) : ```python #!/usr/bin/env python3 import mailbox import csv from email.header import decode_header from email.utils import parsedate_to_datetime def mbox_to_csv(mbox_path, csv_path): """ Exporter les métadonnées mbox vers CSV """ mbox = mailbox.mbox(mbox_path) with open(csv_path, 'w', newline='', encoding='utf-8') as csvfile: writer = csv.writer(csvfile) # En-têtes writer.writerow(['Index', 'Date', 'De', 'À', 'Sujet', 'Taille']) for i, message in enumerate(mbox): # Décoder l'objet subject = message.get('Subject', '') if subject: decoded = decode_header(subject)[0][0] if isinstance(decoded, bytes): subject = decoded.decode('utf-8', errors='ignore') # Date date_str = message.get('Date', '') try: date_obj = parsedate_to_datetime(date_str) date_formatted = date_obj.strftime('%Y-%m-%d %H:%M:%S') except: date_formatted = date_str # Taille du message size = len(str(message)) writer.writerow([ i + 1, date_formatted, message.get('From', ''), message.get('To', ''), subject, size ]) print(f"Export CSV terminé: {csv_path}") # Utilisation mbox_to_csv('/path/to/gmail.mbox', '/path/to/emails_metadata.csv') ``` ## 4. Extraction des pièces jointes ```python #!/usr/bin/env python3 import mailbox import os import email def extract_attachments(mbox_path, output_dir): """ Extraire toutes les pièces jointes d'un fichier mbox """ if not os.path.exists(output_dir): os.makedirs(output_dir) mbox = mailbox.mbox(mbox_path) attachment_count = 0 for i, message in enumerate(mbox): if message.is_multipart(): for part in message.walk(): # Vérifier si c'est une pièce jointe if part.get_content_disposition() == 'attachment': filename = part.get_filename() if filename: # Nettoyer le nom de fichier filename = f"{i:04d}_{filename}" filepath = os.path.join(output_dir, filename) # Sauvegarder la pièce jointe with open(filepath, 'wb') as f: f.write(part.get_payload(decode=True)) print(f"Pièce jointe extraite: {filename}") attachment_count += 1 print(f"Total des pièces jointes extraites: {attachment_count}") # Utilisation extract_attachments('/path/to/gmail.mbox', '/path/to/attachments/') ``` ## 5. Recherche dans le fichier mbox ```python #!/usr/bin/env python3 import mailbox import re from email.header import decode_header def search_mbox(mbox_path, search_term, search_in=['subject', 'body', 'from']): """ Rechercher dans un fichier mbox """ mbox = mailbox.mbox(mbox_path) results = [] for i, message in enumerate(mbox): found = False # Recherche dans l'objet if 'subject' in search_in: subject = message.get('Subject', '') if subject and search_term.lower() in subject.lower(): found = True # Recherche dans l'expéditeur if 'from' in search_in: from_addr = message.get('From', '') if search_term.lower() in from_addr.lower(): found = True # Recherche dans le corps if 'body' in search_in: if message.is_multipart(): for part in message.walk(): if part.get_content_type() == "text/plain": body = part.get_payload(decode=True) if body and search_term.lower() in body.decode('utf-8', errors='ignore').lower(): found = True break else: body = message.get_payload(decode=True) if body and search_term.lower() in body.decode('utf-8', errors='ignore').lower(): found = True if found: subject = decode_header(message.get('Subject', ''))[0][0] if isinstance(subject, bytes): subject = subject.decode('utf-8', errors='ignore') results.append({ 'index': i + 1, 'subject': subject, 'from': message.get('From', ''), 'date': message.get('Date', '') }) return results # Utilisation results = search_mbox('/path/to/gmail.mbox', 'contrat', ['subject', 'body']) for result in results: print(f"Email {result['index']}: {result['subject']} - {result['from']}") ``` ## 6. Outils recommandés par plateforme ### Windows : - **Thunderbird** (gratuit, multiplateforme) - **MailStore Home** (gratuit pour usage personnel) - **Outlook** (avec conversion préalable) ### macOS : - **Apple Mail** (intégré) - **Thunderbird** (gratuit) ### Linux : - **Thunderbird** (recommandé) - **Evolution** (GNOME) - **mutt** (ligne de commande) - **Scripts Python** (pour traitement automatisé) ## 7. Troubleshooting ### Problème : Fichier mbox corrompu ```bash # Vérifier l'intégrité file gmail.mbox head -n 10 gmail.mbox # Réparer si nécessaire (supprimer les caractères problématiques) sed 's/\x00//g' gmail.mbox > gmail_clean.mbox ``` ### Problème : Encodage des caractères ```python # Forcer l'encodage UTF-8 with open('gmail.mbox', 'r', encoding='utf-8', errors='ignore') as f: content = f.read() ``` ### Problème : Fichier trop volumineux ```bash # Diviser le fichier mbox split -l 1000 gmail.mbox gmail_part_ # Chaque partie peut ensuite être importée séparément ``` ## 8. Scripts utilitaires complets ### Script d'analyse complète d'un fichier mbox : ```python #!/usr/bin/env python3 import mailbox import os import sys from email.header import decode_header from email.utils import parsedate_to_datetime from collections import Counter import argparse def analyze_mbox(mbox_path): """ Analyser complètement un fichier mbox """ if not os.path.exists(mbox_path): print(f"Erreur: Le fichier {mbox_path} n'existe pas") return print(f"Analyse du fichier: {mbox_path}") print("=" * 50) mbox = mailbox.mbox(mbox_path) total_emails = 0 total_size = 0 senders = Counter() years = Counter() months = Counter() has_attachments = 0 for message in mbox: total_emails += 1 total_size += len(str(message)) # Analyser l'expéditeur sender = message.get('From', 'Inconnu') senders[sender] += 1 # Analyser la date date_str = message.get('Date', '') try: date_obj = parsedate_to_datetime(date_str) years[date_obj.year] += 1 months[f"{date_obj.year}-{date_obj.month:02d}"] += 1 except: pass # Vérifier les pièces jointes if message.is_multipart(): for part in message.walk(): if part.get_content_disposition() == 'attachment': has_attachments += 1 break # Affichage des statistiques print(f"Nombre total d'emails: {total_emails}") print(f"Taille totale: {total_size / (1024*1024):.2f} MB") print(f"Emails avec pièces jointes: {has_attachments}") print(f"Taille moyenne par email: {total_size / total_emails / 1024:.2f} KB") print("\nTop 10 des expéditeurs:") for sender, count in senders.most_common(10): print(f" {count:4d} - {sender}") print("\nRépartition par année:") for year in sorted(years.keys()): print(f" {year}: {years[year]} emails") print("\nDerniers mois:") for month in sorted(months.keys())[-12:]: print(f" {month}: {months[month]} emails") def main(): parser = argparse.ArgumentParser(description='Analyser un fichier mbox') parser.add_argument('mbox_file', help='Chemin vers le fichier mbox') args = parser.parse_args() analyze_mbox(args.mbox_file) if __name__ == "__main__": main() ``` ### Script de conversion universelle : ```python #!/usr/bin/env python3 import mailbox import os import argparse import json from email.header import decode_header def convert_mbox(mbox_path, output_format, output_dir): """ Convertir un fichier mbox vers différents formats """ if not os.path.exists(output_dir): os.makedirs(output_dir) mbox = mailbox.mbox(mbox_path) if output_format == 'eml': convert_to_eml(mbox, output_dir) elif output_format == 'json': convert_to_json(mbox, output_dir) elif output_format == 'txt': convert_to_txt(mbox, output_dir) else: print(f"Format {output_format} non supporté") def convert_to_eml(mbox, output_dir): """Convertir vers des fichiers EML individuels""" for i, message in enumerate(mbox): filename = f"{i:06d}.eml" with open(os.path.join(output_dir, filename), 'w', encoding='utf-8') as f: f.write(str(message)) print(f"Exporté: {filename}") def convert_to_json(mbox, output_dir): """Convertir vers JSON""" emails = [] for i, message in enumerate(mbox): email_data = { 'index': i, 'subject': decode_header_safe(message.get('Subject', '')), 'from': message.get('From', ''), 'to': message.get('To', ''), 'date': message.get('Date', ''), 'body': extract_body(message) } emails.append(email_data) with open(os.path.join(output_dir, 'emails.json'), 'w', encoding='utf-8') as f: json.dump(emails, f, indent=2, ensure_ascii=False) print(f"Exporté: emails.json ({len(emails)} emails)") def decode_header_safe(header): """Décoder un header de manière sécurisée""" try: decoded = decode_header(header)[0][0] if isinstance(decoded, bytes): return decoded.decode('utf-8', errors='ignore') return decoded except: return header def extract_body(message): """Extraire le corps d'un message""" if message.is_multipart(): for part in message.walk(): if part.get_content_type() == "text/plain": body = part.get_payload(decode=True) if body: return body.decode('utf-8', errors='ignore') else: body = message.get_payload(decode=True) if body: return body.decode('utf-8', errors='ignore') return "" def main(): parser = argparse.ArgumentParser(description='Convertir un fichier mbox') parser.add_argument('mbox_file', help='Fichier mbox source') parser.add_argument('format', choices=['eml', 'json', 'txt'], help='Format de sortie') parser.add_argument('output_dir', help='Répertoire de sortie') args = parser.parse_args() convert_mbox(args.mbox_file, args.format, args.output_dir) if __name__ == "__main__": main() ``` ## 9. Utilisation avec Thunderbird (Détaillée) ### Import pas à pas : 1. **Télécharger ImportExportTools NG** : ``` https://addons.thunderbird.net/addon/importexporttools-ng/ ``` 2. **Installation de l'extension** : - Outils → Modules complémentaires - Installer depuis un fichier - Redémarrer Thunderbird 3. **Import du fichier mbox** : - Créer un nouveau dossier local - Clic droit → ImportExportTools NG - Importer fichier mbox - Sélectionner le fichier de Google Takeout 4. **Vérification** : - Compter les emails importés - Vérifier quelques emails au hasard - Tester la recherche --- **Note importante** : Le format .mbox de Google Takeout est un standard ouvert qui peut être lu par la plupart des clients email. Thunderbird reste la solution la plus simple et fiable pour ouvrir ces fichiers. ## 10. Reconstitution de l'arborescence Gmail ### Pourquoi l'arborescence est perdue : 1. **Format historique** : .mbox date des années 1970, avant les dossiers hierarchiques 2. **Gmail utilise des labels** : Pas de vraie hiérarchie de dossiers 3. **Un seul fichier** : Tous les emails dans un flux continu 4. **Pas de métadonnées de structure** : Le format ne stocke pas l'organisation visuelle ### Script pour extraire les labels Gmail : ```python #!/usr/bin/env python3 import mailbox import re from collections import defaultdict def extract_gmail_structure(mbox_path): """ Extraire la structure des labels Gmail depuis un fichier mbox """ mbox = mailbox.mbox(mbox_path) folders = defaultdict(list) conversations = defaultdict(list) for i, message in enumerate(mbox): # Extraire les labels Gmail gmail_labels = message.get('X-Gmail-Labels', '') if gmail_labels: labels = [label.strip() for label in gmail_labels.split(',')] for label in labels: # Nettoyer les labels système Gmail clean_label = clean_gmail_label(label) if clean_label: folders[clean_label].append({ 'index': i, 'subject': message.get('Subject', ''), 'from': message.get('From', ''), 'date': message.get('Date', ''), 'message_id': message.get('Message-ID', '') }) # Identifier les conversations msg_id = message.get('Message-ID', '') in_reply_to = message.get('In-Reply-To', '') references = message.get('References', '') if in_reply_to or references: thread_id = in_reply_to or references.split()[0] if references else msg_id conversations[thread_id].append({ 'message_id': msg_id, 'subject': message.get('Subject', ''), 'index': i }) return folders, conversations def clean_gmail_label(label): """ Nettoyer les labels système Gmail """ # Labels système à ignorer system_labels = { 'INBOX', 'SENT', 'DRAFT', 'SPAM', 'TRASH', 'UNREAD', 'STARRED', 'IMPORTANT', 'CATEGORY_PERSONAL', 'CATEGORY_SOCIAL', 'CATEGORY_PROMOTIONS', 'CATEGORY_UPDATES', 'CATEGORY_FORUMS' } if label in system_labels: return None # Décoder les labels avec caractères spéciaux if label.startswith('"') and label.endswith('"'): label = label[1:-1] return label def generate_folder_structure(folders): """ Générer une structure de dossiers lisible """ print("Structure des dossiers extraite de Gmail:") print("=" * 50) for folder_name, emails in sorted(folders.items()): print(f"\n📁 {folder_name} ({len(emails)} emails)") # Afficher les 5 premiers emails du dossier for email in emails[:5]: subject = email['subject'][:50] + "..." if len(email['subject']) > 50 else email['subject'] print(f" 📧 {subject} - {email['from']}") if len(emails) > 5: print(f" ... et {len(emails) - 5} autres emails") # Utilisation folders, conversations = extract_gmail_structure('/path/to/gmail.mbox') generate_folder_structure(folders) ``` ### Reconstitution pour Thunderbird : ```python #!/usr/bin/env python3 import mailbox import os def create_thunderbird_folders(mbox_path, output_dir): """ Créer des fichiers mbox séparés par label pour Thunderbird """ if not os.path.exists(output_dir): os.makedirs(output_dir) mbox = mailbox.mbox(mbox_path) folders = {} # Créer des fichiers mbox par label for message in mbox: gmail_labels = message.get('X-Gmail-Labels', '') if gmail_labels: labels = [label.strip() for label in gmail_labels.split(',')] for label in labels: clean_label = clean_gmail_label(label) if clean_label: # Créer le fichier mbox pour ce label s'il n'existe pas if clean_label not in folders: folder_path = os.path.join(output_dir, f"{clean_label}.mbox") folders[clean_label] = mailbox.mbox(folder_path) # Ajouter le message au dossier approprié folders[clean_label].add(message) # Fermer tous les fichiers for folder in folders.values(): folder.close() print(f"Dossiers créés dans {output_dir}:") for folder_name in folders.keys(): print(f" - {folder_name}.mbox") # Utilisation create_thunderbird_folders('/path/to/gmail.mbox', '/path/to/thunderbird_folders/') ``` ### Alternatives pour préserver l'arborescence : #### 1. **Export par dossier Gmail** : - Utiliser Google Takeout en sélectionnant "Inclure tous les messages dans Mail" - Choisir "Exporter par dossier" si disponible #### 2. **Scripts d'export personnalisés** : ```python # Utiliser l'API Gmail pour exporter avec structure from googleapiclient.discovery import build def export_with_structure(service, user_id='me'): """ Exporter avec préservation de la structure """ # Lister tous les labels labels = service.users().labels().list(userId=user_id).execute() for label in labels['labels']: label_id = label['id'] label_name = label['name'] # Exporter les messages de ce label messages = service.users().messages().list( userId=user_id, labelIds=[label_id] ).execute() # Créer un fichier mbox pour ce label # ... code d'export ... ``` ### Recommandations pratiques : #### Pour une migration complète : 1. **Utiliser l'API Gmail** directement plutôt que Takeout 2. **Exporter par labels** avec scripts personnalisés 3. **Documenter la structure** avant export 4. **Reconstituer manuellement** les dossiers importants #### Pour l'archivage simple : 1. **Accepter la perte de structure** pour l'archivage légal 2. **Utiliser les labels** dans les métadonnées pour retrouver les emails 3. **Créer un index** des emails importants avec leurs labels ## 11. Conversion mbox vers Maildir (format Dovecot) Le format **Maildir** est utilisé par de nombreux serveurs de messagerie modernes comme Dovecot, Postfix, et Courier. Contrairement au format mbox (un seul fichier), Maildir stocke chaque email dans un fichier séparé. ### Avantages du format Maildir : - **Sécurité** : Pas de corruption si un email est corrompu - **Performance** : Accès plus rapide aux emails individuels - **Concurrence** : Plusieurs processus peuvent accéder simultanément - **Fiabilité** : Moins de risques de perte de données ### Structure Maildir : ``` Maildir/ ├── cur/ # Messages lus ├── new/ # Messages non lus ├── tmp/ # Messages temporaires └── .Subfolder/ # Sous-dossiers (avec point en préfixe) ├── cur/ ├── new/ └── tmp/ ``` ### Méthode 1 : Avec Python (Script personnalisé) #### Script de conversion complet : ```python #!/usr/bin/env python3 import mailbox import os import time import email.utils import hashlib import sys from pathlib import Path def mbox_to_maildir(mbox_path, maildir_path): """ Convertir un fichier mbox vers le format Maildir """ # Créer la structure Maildir create_maildir_structure(maildir_path) # Ouvrir le fichier mbox source mbox = mailbox.mbox(mbox_path) maildir = mailbox.Maildir(maildir_path) print(f"Conversion de {mbox_path} vers {maildir_path}") print("=" * 50) converted_count = 0 error_count = 0 for i, message in enumerate(mbox): try: # Ajouter le message au Maildir key = maildir.add(message) converted_count += 1 if converted_count % 100 == 0: print(f"Converti {converted_count} messages...") except Exception as e: print(f"Erreur pour le message {i}: {e}") error_count += 1 print(f"\nConversion terminée:") print(f" Messages convertis: {converted_count}") print(f" Erreurs: {error_count}") print(f" Maildir créé dans: {maildir_path}") def create_maildir_structure(maildir_path): """ Créer la structure de base d'un Maildir """ Path(maildir_path).mkdir(parents=True, exist_ok=True) Path(maildir_path, 'cur').mkdir(exist_ok=True) Path(maildir_path, 'new').mkdir(exist_ok=True) Path(maildir_path, 'tmp').mkdir(exist_ok=True) def mbox_to_maildir_with_labels(mbox_path, base_maildir_path): """ Convertir mbox vers Maildir en créant des sous-dossiers par label Gmail """ mbox = mailbox.mbox(mbox_path) # Analyser les labels d'abord labels_map = analyze_gmail_labels(mbox_path) # Créer le Maildir principal create_maildir_structure(base_maildir_path) main_maildir = mailbox.Maildir(base_maildir_path) # Créer les sous-dossiers Maildir pour chaque label label_maildirs = {} for label in labels_map.keys(): if label and label not in ['INBOX', 'SENT', 'DRAFT']: label_path = os.path.join(base_maildir_path, f'.{label}') create_maildir_structure(label_path) label_maildirs[label] = mailbox.Maildir(label_path) print(f"Conversion avec labels vers {base_maildir_path}") print("=" * 50) # Convertir les messages for i, message in enumerate(mbox): try: # Ajouter au Maildir principal main_maildir.add(message) # Extraire les labels Gmail gmail_labels = message.get('X-Gmail-Labels', '') if gmail_labels: labels = [label.strip() for label in gmail_labels.split(',')] for label in labels: clean_label = clean_gmail_label(label) if clean_label and clean_label in label_maildirs: # Ajouter aussi au sous-dossier correspondant label_maildirs[clean_label].add(message) if (i + 1) % 100 == 0: print(f"Converti {i + 1} messages...") except Exception as e: print(f"Erreur pour le message {i}: {e}") # Fermer tous les Maildir main_maildir.close() for md in label_maildirs.values(): md.close() print(f"\nConversion terminée avec {len(label_maildirs)} sous-dossiers") def analyze_gmail_labels(mbox_path): """ Analyser les labels Gmail présents dans le mbox """ mbox = mailbox.mbox(mbox_path) labels_count = {} for message in mbox: gmail_labels = message.get('X-Gmail-Labels', '') if gmail_labels: labels = [label.strip() for label in gmail_labels.split(',')] for label in labels: clean_label = clean_gmail_label(label) if clean_label: labels_count[clean_label] = labels_count.get(clean_label, 0) + 1 return labels_count def clean_gmail_label(label): """ Nettoyer les labels Gmail pour les noms de dossiers """ system_labels = { 'INBOX', 'SENT', 'DRAFT', 'SPAM', 'TRASH', 'UNREAD', 'STARRED', 'IMPORTANT', 'CATEGORY_PERSONAL', 'CATEGORY_SOCIAL', 'CATEGORY_PROMOTIONS', 'CATEGORY_UPDATES', 'CATEGORY_FORUMS' } if label in system_labels: return None # Nettoyer le nom pour le système de fichiers clean = label.replace('"', '').replace('/', '_').replace(' ', '_') return clean if clean else None def main(): if len(sys.argv) < 3: print("Usage: python3 mbox2maildir.py [--with-labels]") sys.exit(1) mbox_path = sys.argv[1] maildir_path = sys.argv[2] with_labels = len(sys.argv) > 3 and sys.argv[3] == '--with-labels' if not os.path.exists(mbox_path): print(f"Erreur: Le fichier {mbox_path} n'existe pas") sys.exit(1) if with_labels: mbox_to_maildir_with_labels(mbox_path, maildir_path) else: mbox_to_maildir(mbox_path, maildir_path) if __name__ == "__main__": main() ``` ### Méthode 2 : Avec mb2md (outil spécialisé) #### Installation : ```bash # Sur Ubuntu/Debian sudo apt install mb2md # Sur CentOS/RHEL sudo yum install mb2md # Ou téléchargement manuel wget http://batleth.sapienti-sat.org/projects/mb2md/mb2md-3.20.pl chmod +x mb2md-3.20.pl ``` #### Utilisation : ```bash # Conversion simple mb2md -s /path/to/gmail.mbox -d /path/to/maildir # Avec création de sous-dossiers mb2md -s /path/to/gmail.mbox -d /path/to/maildir -R # Verbose pour voir le progrès mb2md -s /path/to/gmail.mbox -d /path/to/maildir -v ``` ### Méthode 3 : Avec formail et procmail #### Script bash utilisant formail : ```bash #!/bin/bash # Convertir mbox vers Maildir avec formail MBOX_FILE="$1" MAILDIR_PATH="$2" if [ -z "$MBOX_FILE" ] || [ -z "$MAILDIR_PATH" ]; then echo "Usage: $0 " exit 1 fi # Créer la structure Maildir mkdir -p "$MAILDIR_PATH"/{cur,new,tmp} echo "Conversion de $MBOX_FILE vers $MAILDIR_PATH" # Utiliser formail pour séparer les messages cat "$MBOX_FILE" | formail -ds sh -c ' # Générer un nom de fichier unique TIMESTAMP=$(date +%s) RANDOM_NUM=$RANDOM HOSTNAME=$(hostname) FILENAME="${TIMESTAMP}.${RANDOM_NUM}.${HOSTNAME}" # Sauvegarder le message dans new/ cat > "'$MAILDIR_PATH'/new/$FILENAME" echo "Message sauvé: $FILENAME" ' echo "Conversion terminée" echo "Messages dans: $MAILDIR_PATH/new/" ls -1 "$MAILDIR_PATH/new/" | wc -l | xargs echo "Nombre de messages:" ``` ### Méthode 4 : Avec Dovecot dsync #### Si Dovecot est installé : ```bash # Créer une configuration temporaire Dovecot cat > /tmp/dovecot-convert.conf << EOF mail_location = mbox:~/mbox:INBOX=/path/to/gmail.mbox namespace inbox { inbox = yes location = mailbox Drafts { special_use = \Drafts } mailbox Junk { special_use = \Junk } mailbox Sent { special_use = \Sent } mailbox "Sent Messages" { special_use = \Sent } mailbox Trash { special_use = \Trash } prefix = } EOF # Conversion avec dsync doveadm -c /tmp/dovecot-convert.conf backup -u user@domain.com maildir:/path/to/output/maildir ``` ### Vérification de la conversion #### Script de vérification : ```python #!/usr/bin/env python3 import mailbox import os def verify_conversion(mbox_path, maildir_path): """ Vérifier que la conversion mbox -> maildir est correcte """ print("Vérification de la conversion") print("=" * 30) # Compter les messages dans le mbox original mbox = mailbox.mbox(mbox_path) mbox_count = len(mbox) print(f"Messages dans mbox: {mbox_count}") # Compter les messages dans le Maildir maildir = mailbox.Maildir(maildir_path) maildir_count = len(maildir) print(f"Messages dans Maildir: {maildir_count}") # Vérifier la structure cur_count = len(os.listdir(os.path.join(maildir_path, 'cur'))) new_count = len(os.listdir(os.path.join(maildir_path, 'new'))) print(f" - Dans cur/: {cur_count}") print(f" - Dans new/: {new_count}") # Résultat if mbox_count == maildir_count: print("✅ Conversion réussie!") else: print(f"❌ Différence détectée: {mbox_count - maildir_count} messages") return mbox_count == maildir_count # Utilisation verify_conversion('/path/to/gmail.mbox', '/path/to/maildir') ``` ### Optimisations et bonnes pratiques #### Pour de gros fichiers mbox : ```python def mbox_to_maildir_chunked(mbox_path, maildir_path, chunk_size=1000): """ Conversion par chunks pour économiser la mémoire """ mbox = mailbox.mbox(mbox_path) maildir = mailbox.Maildir(maildir_path) count = 0 for message in mbox: maildir.add(message) count += 1 if count % chunk_size == 0: print(f"Traité {count} messages...") # Forcer l'écriture maildir.flush() maildir.close() print(f"Conversion terminée: {count} messages") ``` #### Préservation des métadonnées : ```python def preserve_metadata(message, maildir_path, filename): """ Préserver les métadonnées lors de la conversion """ # Extraire la date du message date_str = message.get('Date', '') if date_str: try: import email.utils timestamp = email.utils.mktime_tz(email.utils.parsedate_tz(date_str)) # Appliquer la date au fichier filepath = os.path.join(maildir_path, 'new', filename) os.utime(filepath, (timestamp, timestamp)) except: pass ``` ### Utilisation avec différents serveurs #### Pour Dovecot : ```bash # Configuration dans dovecot.conf mail_location = maildir:~/Maildir # Test de la configuration doveadm mailbox list -u user@domain.com ``` #### Pour Postfix + Dovecot : ```bash # Dans main.cf home_mailbox = Maildir/ # Redémarrage des services systemctl restart postfix dovecot ``` #### Pour Courier : ```bash # Courier utilise maildir par défaut # Configuration dans /etc/courier/authdaemonrc ``` ### Commandes utiles post-conversion ```bash # Statistiques du Maildir find /path/to/maildir -name "*" -type f | wc -l # Vérifier l'intégrité for dir in cur new tmp; do echo "$dir: $(ls /path/to/maildir/$dir | wc -l) messages" done # Indexation Dovecot (si applicable) doveadm index -u user@domain.com INBOX # Reconstruction des index doveadm force-resync -u user@domain.com '*' ``` **Date de création** : 22 octobre 2025