> Pour un agent : la carte de la documentation d'Escouade Mail est sur https://escouade.io/mail/docs/llms.txt ; chaque page existe en Markdown, à la même adresse suffixée `.md`.

# `reply_to_thread`

> Répond dans un fil existant, au correspondant du fil : sujet « Re: … » et en-têtes In-Reply-To / References corrects, pour que la réponse s’affiche dans la même conversation chez le destinataire.

## En bref

| Propriété | Valeur |
|---|---|
| Titre | Répondre dans un fil |
| Outil MCP | `reply_to_thread`, sur `https://api.subagent.fr/mcp` |
| Appelé par | l’assistant et la vue |
| Appel HTTP | `POST https://api.subagent.fr/v1/reply_to_thread` |
| Accès | permission `send` |
| État de l'espace | vérifié : sinon, refus `space_unverified` |
| Effet | écriture |
| Vue dans l'assistant | non |

## Ce que fait l'outil

Le serveur décrit l'outil ainsi à l'agent qui se branche :

> Répond dans un fil existant, au correspondant du fil : sujet « Re: … » et en-têtes In-Reply-To / References corrects, pour que la réponse s’affiche dans la même conversation chez le destinataire. Sert aussi à relancer : une réponse dans un fil n’est pas soumise à la règle de doublon, mais reste soumise au blocage, aux quotas, au créneau et à la validation humaine. Dès que le correspondant a écrit dans le fil, c’est une conversation : la réponse part sans attendre le créneau et sans pied de désinscription (le lien en un clic reste dans ses en-têtes) ; elle compte toujours dans le quota du jour, respecte l’étalement entre deux envois et reste soumise au blocage et à la validation humaine.

## Paramètres

`reply_to_thread` accepte ces paramètres. Un paramètre inconnu est refusé avec le code `invalid_argument`.

| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
| `thread_id` | identifiant `thr_…` | oui | Le fil (thr_…, voir `list_threads`). |
| `subject` | texte | non | Sujet, facultatif : « Re: » + sujet du fil par défaut. 300 caractères au plus. |
| `cc` | liste | non | Adresses en copie : seulement si le correspondant a déjà écrit dans le fil, vers quelqu’un qui y a lui aussi écrit ou une adresse de l’espace. |
| `from_address` | texte | non | Adresse principale ou alias autorisé de la boîte (`list_inboxes`). |
| `text` | texte | oui | Texte brut du message (obligatoire). Écrivez `{{unsubscribe_url}}` pour placer vous-même le lien de désinscription ; sinon Subagent ajoute une mention en pied, tant que le correspondant n’a pas écrit dans le fil. Aucun autre `{{champ}}` n’est accepté : remplacez-les avant. |
| `html` | texte | non | Version HTML facultative, même contenu que text. |
| `reply_to` | texte | non | Adresse de réponse, si elle diffère de la boîte. |
| `metadata` | objet | non | Données libres de l’agent (8 000 caractères au plus), rendues telles quelles dans les lectures. |
| `requires_approval` | booléen | non | `true` : le message reste brouillon jusqu’à ce qu’un humain le valide (`approve_message`). Certains espaces l’imposent toujours. |
| `send_after` | date | non | Pas avant cette date (ISO 8601, ou heure de Paris sans fuseau). Le créneau (sauf pour une réponse dans une conversation) et les quotas s’appliquent ensuite. |
| `idempotency_key` | texte | non | Clé unique de cet envoi (1 à 255 caractères). Rejouer la même clé avec le même contenu rend le message déjà créé ; avec un contenu différent, refus explicite. Recommandée pour tout réessai. |

## Résultat

L'outil rend un texte lisible en français et un objet structuré (`structuredContent`). En HTTP, la réponse est cet objet.

| Champ | Type | Contenu |
|---|---|---|
| `estimated_send_at` | texte ou `null` | Départ au plus tôt (estimation : créneau, étalement, quota). |
| `inbox` | objet | Une boîte. Voir [les champs d'une boîte](https://escouade.io/mail/docs/boites.md#champs). |
| `message` | objet | Un message. Voir [les champs d'un message](https://escouade.io/mail/docs/messages.md#champs). |
| `replayed` | booléen | `true` : même clé d’idempotence et même contenu, rien de nouveau n’a été créé. |
| `thread` | objet | Un fil. Voir [les champs d'un fil](https://escouade.io/mail/docs/fils.md#champs). |

## Exemple d'appel

Les valeurs sont fictives.

HTTP :

```sh
curl -X POST https://api.subagent.fr/v1/reply_to_thread \
  -H "Authorization: Bearer $SUBAGENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "thread_id": "thr_b81f4c6a2d9e47035c1a8e6f0b4d2c97",
  "text": "Bonjour Madame Morel,\n\nC'\''est noté pour vendredi, à la même heure.\n\nAtelier Exemple",
  "idempotency_key": "rdv-morel-reponse-1"
}'
```

MCP (`tools/call`) :

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "reply_to_thread",
    "arguments": {
      "thread_id": "thr_b81f4c6a2d9e47035c1a8e6f0b4d2c97",
      "text": "Bonjour Madame Morel,\n\nC'est noté pour vendredi, à la même heure.\n\nAtelier Exemple",
      "idempotency_key": "rdv-morel-reponse-1"
    }
  }
}
```

## Refus possibles

| Code | HTTP | Ce qui s'est passé | Que faire |
|---|---|---|---|
| `space_unverified` | 403 | L'espace n'est pas vérifié : ses boîtes reçoivent, mais n'envoient pas. | Demander à l'humain le code à 6 chiffres, puis appeler `verify`. S'il n'a rien reçu, ou si aucun e-mail n'est rattaché à l'espace : `attach_human`. |
| `payment_required` | 402 | L'espace n'a pas de forfait en cours : sa boîte reçoit, prépare des brouillons et n'écrit qu'à son humain. Le refus vaut pour un envoi à un tiers, la validation d'un brouillon, une seconde boîte et `add_domain`. | Appeler `subscribe`, après l'accord de l'humain, et lui remettre le lien de paiement. Ensuite, `billing_status` dit si le forfait est en cours. |
| `own_domain_required` | 422 | La boîte est sur le domaine commun : elle ne fait que répondre à qui lui a écrit. Un premier message, ou une relance sans réponse, n'en part pas. | Enregistrer le domaine de l'humain (`add_domain`), le faire vérifier (`verify_domain`), y créer une boîte (`create_inbox`) et écrire depuis elle. |
| `not_found` | 404 | L'objet n'existe pas pour cette clé. | Vérifier l'identifiant : il vient de `list_inboxes`, `list_threads`, `get_thread` ou `list_drafts`. |
| `recipient_suppressed` | 422 | Le destinataire est bloqué : désinscription, plainte, adresse morte ou blocage manuel. | Ne plus écrire à cette adresse, depuis aucune boîte. |
| `cc_not_allowed` | 409 | Le correspondant n'a pas encore écrit dans le fil, ou l'adresse n'y a pas écrit elle-même et n'est pas une adresse de l'espace. | Répondre sans copie, ou mettre en copie une adresse qui a écrit dans le fil. |
| `key_daily_cap` | 429 | Le plafond de messages par jour de la clé est atteint. | Reprendre le lendemain, à partir de 0 h, heure de Paris. |
| `inbox_suspended` | 409 | Le coupe-circuit a suspendu la boîte. La raison est dans le message. | Vérifier la liste de destinataires. La reprise est manuelle, par un administrateur d'Escouade Mail : l'humain la demande avec `request_inbox_review`. |
| `domain_not_verified` | 409 | Le domaine de la boîte n'est pas encore vérifié. | Publier ses enregistrements DNS, puis appeler `verify_domain`. |
| `domain_suspended` | 409 | Un enregistrement DNS exigé a disparu : le domaine est suspendu, ses boîtes n'envoient plus. | Remettre les enregistrements en place (`list_domains` les donne), puis appeler `verify_domain`. |
| `unresolved_placeholder` | 422 | Un champ entre doubles accolades est resté dans le sujet ou le texte. | Remplacer chaque champ par sa valeur. Seul `{{unsubscribe_url}}` est accepté. |
| `idempotency_conflict` | 409 | La même `idempotency_key` a déjà servi pour un contenu différent. | Même message : réutiliser la clé telle quelle. Nouveau message : en prendre une nouvelle. |
| `queue_full` | 429 | La file de la boîte est pleine : trop de brouillons et de messages en attente (dix fois son quota maximal du jour). | Laisser partir les messages en attente, ou annuler ceux qui ne servent plus avec `cancel_message`. |
| `domain_sending_not_included` | 402 | L'organisation est en Gratuit : sa boîte reçoit et n'écrit qu'à son humain, l'envoi depuis son domaine n'y est pas compris. Rien n'a été créé. | Écrire à son humain avec `send_email` et `test` = `true`. Pour écrire à un tiers : passer à la taille Essentiel (800 e-mails par mois) depuis le compte Escouade. |
| `emails_quota` | 402 | Le compteur e-mails de l'organisation refuse l'envoi : le message en donne la raison. Rien n'a été créé. | Sur la page Utilisation du compte Escouade, donnée par la piste : activer les crédits, relever leur plafond ou passer à la taille supérieure, puis réessayer. |
| `escouade_unavailable` | 503 | Les droits de l'organisation ne sont pas lisibles (jamais relevés, ou échus), ou son compteur ne répond pas et l'espace n'a pas d'avance pour envoyer sans lui. Rien n'a été créé. | Réessayer dans quelques minutes, avec la même `idempotency_key`. Si le refus dure, prévenir un administrateur d'Escouade. |

S'y ajoutent les refus communs à tous les outils (`unauthorized`, `forbidden`, `invalid_argument`, `rate_limited`, `internal`) : voir [Erreurs](https://escouade.io/mail/docs/erreurs.md#acces).

## Voir aussi

- [Fils : reply_to_thread](https://escouade.io/mail/docs/fils.md#reply_to_thread)
- [Guide : répondre à un correspondant](https://escouade.io/mail/docs/guide-repondre.md)
- [`get_thread`](https://escouade.io/mail/docs/reference/get_thread.md)
- [`send_email`](https://escouade.io/mail/docs/reference/send_email.md)
- [`cancel_message`](https://escouade.io/mail/docs/reference/cancel_message.md)
- [Tous les outils](https://escouade.io/mail/docs/reference/index.md)
