Skip to content

Latest commit

 

History

History
549 lines (427 loc) · 13.2 KB

API.md

File metadata and controls

549 lines (427 loc) · 13.2 KB

Documentation API MailPilot

Endpoints REST

Health Check

GET /api/health

Vérifie l'état de l'application.

Réponse :

{
  "status": "ok",
  "service": "MailPilot"
}

Liste des emails

GET /api/emails

Récupère la liste des emails.

Paramètres de requête :

  • limit (int, optionnel) : Nombre maximum d'emails à retourner (défaut: 50)
  • folder (string, optionnel) : Dossier logique à lister. Valeurs possibles :
    • inbox (défaut)
    • sent
    • spam
    • trash

Réponse :

{
  "emails": [
    {
      "id": 1,
      "message_id": "<message-id@example.com>",
      "subject": "Demande de devis",
      "sender_email": "client@example.com",
      "sender_name": "Jean Dupont",
      "received_date": "2025-01-28T10:30:00",
      "is_replied": true,
      "is_processed": true,
      "is_read": false,
      "classification": {
        "sender_type": "human",
        "is_commercial": false,
        "company_name": "Example",
        "company_domain": "example.com",
        "confidence": 75
      }
    }
  ]
}

Note : classification est null si la classification n'a pas encore été effectuée. La classification est basée sur le premier email de la conversation.

Détails d'un email

GET /api/emails/<email_id>

Récupère les détails d'un email spécifique.

Réponse :

{
  "id": 1,
  "message_id": "<message-id@example.com>",
  "subject": "Demande de devis",
  "sender_email": "client@example.com",
  "sender_name": "Jean Dupont",
  "body_text": "Bonjour, je souhaite...",
  "body_html": "<p>Bonjour, je souhaite...</p>",
  "received_date": "2025-01-28T10:30:00",
  "is_replied": true,
  "is_read": false,
  "osint": {
    "status": "done",
    "data": {
      "email": "client@example.com",
      "name": "Jean Dupont",
      "sources": ["sherlock", "maigret"],
      "social_profiles": {
        "Twitter": "https://twitter.com/jeandupont",
        "LinkedIn": "https://linkedin.com/in/jeandupont"
      },
      "breach_data": {}
    },
    "updated_date": "2025-01-28T10:32:00"
  },
  "classification": {
    "sender_type": "human",
    "is_commercial": false,
    "company_name": "Example",
    "company_domain": "example.com",
    "confidence": 75
  },
  "response": {
    "id": 1,
    "subject": "Re: Demande de devis",
    "body": "Merci pour votre message...",
    "is_sent": true,
    "sent_date": "2025-01-28T10:35:00",
    "tracking_token": "xxxxxxxx",
    "tracking": {
      "opens": 2,
      "clicks": 1
    }
  }
}

Note :

  • classification vient de la conversation (basée sur le premier email)
  • osint vient de l'identité (Identity) et est réutilisable entre emails
  • Si sender_type == "robot", osint sera généralement null (OSINT non lancé)
  • Les dates créées par l'application (ex. sent_date, received_date pour les réponses envoyées depuis l'UI) sont en fuseau Europe/Paris (naive) pour un affichage cohérent côté client

Suppression d'un email

DELETE /api/emails/<email_id>

Supprime un email : tentative de suppression côté IMAP puis suppression en base. Si la suppression IMAP échoue (connexion, auth, message introuvable), l'email est quand même supprimé en base pour ne pas bloquer l'UI.

Réponse 200 :

{
  "success": true,
  "deleted_on_imap": true
}
  • deleted_on_imap : true si la suppression sur le serveur IMAP a réussi, false sinon (email supprimé uniquement en base).

Réponse 404 : {"error": "Email not found"}

Tracking des emails envoyés (ouvertures, clics)

Les réponses envoyées depuis l'interface et les nouveaux messages envoyés peuvent inclure un pixel invisible et des liens trackés. Lorsque le destinataire ouvre l'email ou clique sur un lien, un événement est enregistré.

GET /api/emails/<email_id>/tracking

Statistiques de tracking pour la réponse envoyée à cet email (ouvertures, clics, temps de lecture).

Réponse 200 :

{
  "email_id": 1,
  "response_id": 5,
  "total_opens": 2,
  "total_clicks": 1,
  "avg_read_time": null,
  "first_open": "2026-01-31T14:00:00",
  "last_open": "2026-01-31T15:30:00",
  "events_by_type": { "open": { "count": 2, "first_at": "...", "last_at": "..." }, "click": { "count": 1, ... } }
}

GET /api/tracking/response/<response_id>

Statistiques de tracking pour une réponse envoyée (même structure, identifiée par response_id).

Routes publiques (sans auth, appelées par le client du destinataire) :

  • GET /track/pixel/<tracking_token> : pixel 1x1 pour enregistrer une ouverture. Retourne une image PNG transparente.
  • GET /track/click/<tracking_token>?url=<encoded_url> : enregistre un clic puis redirige vers l'URL.
  • GET /track/read-time/<tracking_token>?seconds=<n> : enregistre un temps de lecture (optionnel).

La config app.tracking_base_url doit pointer vers l'URL publique de l'application (ex. https://mailpilot.danielcraft.fr) pour que les liens de tracking dans les emails fonctionnent.

Statistiques globales

GET /api/stats

Retourne un agrégat de statistiques pour alimenter la page « Statistiques » de l'interface.

Réponse 200 :

{
  "totals": {
    "received": 120,
    "sent": 45,
    "unreplied": 8,
    "conversations": 30,
    "conversations_active": 12,
    "pending": 3
  },
  "tracking": {
    "tracked_total": 20,
    "opened_count": 15,
    "clicked_count": 5,
    "open_rate": 75.0,
    "click_rate": 33.3
  },
  "activity_7days": [
    { "date": "27/01", "received": 3, "sent": 1 },
    { "date": "28/01", "received": 5, "sent": 2 }
  ],
  "top_senders": [
    { "email": "client@example.com", "name": "Client", "count": 10 }
  ],
  "distribution": {
    "human": 40,
    "robot": 15,
    "commercial": 12
  }
}

Liste des conversations

GET /api/conversations

Récupère la liste des conversations.

Paramètres de requête :

  • limit (int, optionnel) : Nombre maximum de conversations (défaut: 20)

Réponse :

{
  "conversations": [
    {
      "id": 1,
      "thread_id": "<thread-id@example.com>",
      "subject": "Demande de devis",
      "sender_email": "client@example.com",
      "sender_name": "Jean Dupont",
      "email_count": 3,
      "reply_count": 2,
      "last_email_date": "2025-01-28T10:30:00",
      "updated_date": "2025-01-28T10:30:00"
    }
  ]
}

Contacts

GET /api/contacts

Liste les contacts avec recherche et pagination.

Paramètres de requête :

  • q (string, optionnel) : Recherche sur email, nom, entreprise, notes
  • limit (int, optionnel) : Nombre max de contacts (défaut : 50)
  • offset (int, optionnel) : Décalage pour pagination (défaut : 0)

Réponse :

{
  "contacts": [
    {
      "id": 1,
      "email": "client@example.com",
      "display_name": "Jean Dupont",
      "first_name": "Jean",
      "last_name": "Dupont",
      "company": "Example SAS",
      "phone": null,
      "notes": null,
      "data": {
        "classification": { "sender_type": "human", "is_commercial": false, "company_name": "Example" },
        "osint": { "sources": ["sherlock"], "profiles": {}, "leaks": [] }
      },
      "created_at": "2025-01-28T10:00:00",
      "updated_at": "2025-01-28T10:30:00"
    }
  ],
  "total": 42
}

POST /api/contacts

Crée un nouveau contact.

Body JSON :

  • email (string, requis)
  • display_name, first_name, last_name, company, phone, notes (optionnels)
  • data (object, optionnel) : Données OSINT/classification

Réponse : 201 avec l'objet contact créé.

GET /api/contacts/<contact_id>

Récupère un contact par ID.

PATCH /api/contacts/<contact_id>

Met à jour un contact (champs fournis uniquement). Le champ data est fusionné avec l'existant.

DELETE /api/contacts/<contact_id>

Supprime un contact.

GET /api/contacts/export/vcf

Exporte tous les contacts en fichier vCard 3.0 (CardDAV). Réponse : fichier .vcf en téléchargement.


Envoi d'un nouveau message

POST /api/emails/send

Envoie un email depuis l'interface (modale « Nouveau message »). Crée ou met à jour les contacts pour tous les destinataires (À, Cc, Bcc) et injecte le tracking (pixel + liens trackés) comme pour une réponse.

Body JSON :

  • to (string, requis) : Adresse(s) destinataire(s), séparées par des virgules
  • cc (string, optionnel)
  • bcc (string, optionnel)
  • subject (string, requis)
  • body (string, requis)

Réponse succès :

{
  "success": true,
  "sent_email_id": 42,
  "sent_conversation_id": 10
}

Réponse erreur : 400 ou 500 avec message.

L'email envoyé apparaît immédiatement dans le dossier Envoyés (folder=sent) côté UI, sans attendre une éventuelle copie automatique par le serveur SMTP dans le dossier IMAP "Sent".


Réponse à un email (inline)

POST /api/emails/<email_id>/reply

Envoie une réponse à un email depuis l'interface. Crée un message dans le fil (folder=sent) pour l'historique. Côté UI : la boîte de réponse se ferme pendant l'envoi ; en cas d'erreur, elle se rouvre avec le texte non envoyé pour permettre une nouvelle tentative.

Body JSON :

  • body (string) : Corps du message
  • subject (string, optionnel) : Sujet (défaut : Re: sujet de l'email)

Réponse succès : { "success": true }

Historique d'une conversation

GET /api/conversations/<conversation_id>

Récupère l'historique complet d'une conversation.

Réponse :

{
  "conversation_id": 1,
  "history": [
    {
      "id": 1,
      "message_id": "<message-id@example.com>",
      "subject": "Demande de devis",
      "sender_email": "client@example.com",
      "sender_name": "Jean Dupont",
      "body_text": "Bonjour...",
      "received_date": "2025-01-28T10:00:00",
      "is_replied": true,
      "response": {
        "body": "Merci pour votre message...",
        "is_sent": true,
        "sent_date": "2025-01-28T10:05:00"
      }
    }
  ]
}

Événements WebSocket

Connexion

Événement : connect

Émis automatiquement lors de la connexion.

Réponse :

{
  "status": "ok"
}

Nouvel email reçu

Événement : email_received

Émis lorsqu'un nouvel email est détecté via IMAP IDLE ou lorsqu'un message existant est importé/synchronisé (INBOX, Envoyés, Spam, Corbeille).

Données :

{
  "id": 12,
  "message_id": "<message-id@example.com>",
  "subject": "Demande de devis",
  "conversation_id": 3,
  "sender_email": "client@example.com",
  "sender_name": "Jean Dupont",
  "received_date": "2025-01-28T10:30:00",
  "is_read": false,
  "is_replied": false,
  "is_processed": false,
  "folder": "inbox"
}

Progression du traitement

Événement : email_processing

Émis pendant le traitement d'un email.

Données :

{
  "task_id": "abc123",
  "step": "generation",
  "progress": 70
}

Étapes possibles :

  • initialization : Initialisation
  • osint : Enrichissement OSINT
  • danielcraft_context : Récupération contexte danielcraft.fr
  • generation : Génération de la réponse
  • template : Application du template
  • sending : Envoi de la réponse
  • complete : Terminé

Erreur de traitement

Événement : email_error

Émis en cas d'erreur lors du traitement.

Données :

{
  "task_id": "abc123",
  "error": "Erreur de génération"
}

Monitoring de tâche

Événement client : monitor_task

Démarre le monitoring d'une tâche Celery.

Données envoyées :

{
  "task_id": "abc123"
}

Réponses :

  • task_progress : Progression de la tâche
  • task_complete : Tâche terminée
  • task_error : Erreur de tâche

Récupération des conversations

Événement client : get_conversations

Récupère les conversations en temps réel.

Réponse :

{
  "conversations": [
    {
      "id": 1,
      "thread_id": "<thread-id@example.com>",
      "subject": "Demande de devis",
      "sender_email": "client@example.com",
      "email_count": 3,
      "reply_count": 2
    }
  ]
}

Exemples d'utilisation

JavaScript (WebSocket)

const socket = io();

socket.on('connect', () => {
  console.log('Connecté');
});

socket.on('email_received', (data) => {
  console.log('Nouvel email:', data);
});

socket.on('email_processing', (data) => {
  console.log(`Traitement: ${data.step} - ${data.progress}%`);
});

socket.emit('monitor_task', { task_id: 'abc123' });

Python (REST API)

import requests

# Récupérer les emails
response = requests.get('http://localhost:5000/api/emails?limit=10')
emails = response.json()['emails']

# Récupérer une conversation
response = requests.get('http://localhost:5000/api/conversations/1')
conversation = response.json()

Analyse OSINT manuelle

POST /api/osint/email

Lance une analyse OSINT sur une adresse email (page « OSINT email »).

Body JSON :

  • email (string, requis) : Adresse à analyser

Réponse : Résultat texte de l'analyse (outils OSINT côté serveur / WSL).


Codes d'erreur HTTP

  • 200 : Succès
  • 201 : Créé (ex. contact)
  • 400 : Requête invalide
  • 404 : Ressource non trouvée
  • 500 : Erreur serveur

Rate Limiting

Actuellement, aucun rate limiting n'est implémenté. À ajouter en production si nécessaire.