Français
Messages
Les routes sont relatives à <PUBLIC_BASE_URL> ; les corps de requête et de réponse sont en JSON sauf mention contraire. L’authentification, les portées, la pagination et le format des erreurs sont décrits dans les guides de l’API REST.
GET /api/v1/messages
Lister les messages du miroir
La vue à plat du miroir, les plus récents d’abord (pas la boîte par fils), paginée par curseur. q cherche l’objet, l’aperçu et l’expéditeur, avec la même grammaire que GET /api/v1/threads, et ne sort jamais des boîtes du membre.
Accès — Session de membre ou clé d’API portant messages:read.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
mailboxId | requête | string | non |
cursor | requête | string | non |
limit | requête | integer | non |
q | requête | string | non |
Réponses
200 — Une page de messages.
| Champ | Type | Requis |
|---|---|---|
messages | object[] | oui |
nextCursor | string | null | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"messages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"mailboxId": { "type": "string" },
"from": {
"anyOf": [
{
"type": "object",
"properties": { "name": { "type": "string" }, "email": { "type": "string" } },
"required": [ "email" ],
"additionalProperties": false
},
{ "type": "null" }
]
},
"subject": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"snippet": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"receivedAt": { "type": "string" },
"folderLabels": { "type": "array", "items": { "type": "string" } },
"flags": {
"type": "object",
"properties": {
"seen": { "type": "boolean" },
"flagged": { "type": "boolean" },
"draft": { "type": "boolean" },
"sent": { "type": "boolean" }
},
"required": [ "seen", "flagged", "draft", "sent" ],
"additionalProperties": false
},
"signals": {
"type": "object",
"properties": {
"isAutoReply": { "type": "boolean" },
"isNoReply": { "type": "boolean" },
"isMailingList": { "type": "boolean" },
"isFromSelf": { "type": "boolean" }
},
"required": [ "isAutoReply", "isNoReply", "isMailingList", "isFromSelf" ],
"additionalProperties": false
},
"hasAttachments": { "type": "boolean" }
},
"required": [
"id",
"mailboxId",
"from",
"subject",
"snippet",
"receivedAt",
"folderLabels",
"flags",
"signals",
"hasAttachments"
],
"additionalProperties": false
}
},
"nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [ "messages", "nextCursor" ],
"additionalProperties": false
}400 — La requête ne respecte pas son schéma.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Codes d’erreur — request.bad_request. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
GET /api/v1/messages/{id}
Lire un message
Le message complet : en-têtes, destinataires, liste des pièces jointes et bodyHtmlSafe, assaini à chaque appel et jamais stocké. Ce HTML se rend dans une iframe sandboxée, jamais en ligne.
Accès — Session de membre ou clé d’API portant messages:read.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string (uuid) | oui |
Réponses
200 — Le message.
| Champ | Type | Requis |
|---|---|---|
id | string | oui |
mailboxId | string | oui |
from | object | null | oui |
subject | string | null | oui |
snippet | string | null | oui |
receivedAt | string | oui |
folderLabels | string[] | oui |
flags | object | oui |
signals | object | oui |
hasAttachments | boolean | oui |
threadId | string | null | oui |
classification | object | oui |
bodyText | string | null | oui |
bodyHtmlSafe | string | null | oui |
hasRemoteImages | boolean | oui |
bodyComplete | boolean | oui |
headersSubset | object | oui |
attachments | object[] | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"id": { "type": "string" },
"mailboxId": { "type": "string" },
"from": {
"anyOf": [
{
"type": "object",
"properties": { "name": { "type": "string" }, "email": { "type": "string" } },
"required": [ "email" ],
"additionalProperties": false
},
{ "type": "null" }
]
},
"subject": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"snippet": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"receivedAt": { "type": "string" },
"folderLabels": { "type": "array", "items": { "type": "string" } },
"flags": {
"type": "object",
"properties": {
"seen": { "type": "boolean" },
"flagged": { "type": "boolean" },
"draft": { "type": "boolean" },
"sent": { "type": "boolean" }
},
"required": [ "seen", "flagged", "draft", "sent" ],
"additionalProperties": false
},
"signals": {
"type": "object",
"properties": {
"isAutoReply": { "type": "boolean" },
"isNoReply": { "type": "boolean" },
"isMailingList": { "type": "boolean" },
"isFromSelf": { "type": "boolean" }
},
"required": [ "isAutoReply", "isNoReply", "isMailingList", "isFromSelf" ],
"additionalProperties": false
},
"hasAttachments": { "type": "boolean" },
"threadId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"classification": {
"type": "object",
"propertyNames": { "type": "string" },
"additionalProperties": {}
},
"bodyText": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"bodyHtmlSafe": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"hasRemoteImages": { "type": "boolean" },
"bodyComplete": { "type": "boolean" },
"headersSubset": {
"type": "object",
"properties": {
"to": {
"type": "array",
"items": {
"type": "object",
"properties": { "name": { "type": "string" }, "email": { "type": "string" } },
"required": [ "email" ],
"additionalProperties": false
}
},
"cc": {
"type": "array",
"items": {
"type": "object",
"properties": { "name": { "type": "string" }, "email": { "type": "string" } },
"required": [ "email" ],
"additionalProperties": false
}
},
"replyTo": {
"type": "array",
"items": {
"type": "object",
"properties": { "name": { "type": "string" }, "email": { "type": "string" } },
"required": [ "email" ],
"additionalProperties": false
}
},
"date": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"messageIdHeader": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [ "to", "cc", "replyTo", "date", "messageIdHeader" ],
"additionalProperties": false
},
"attachments": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"position": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"filename": { "type": "string" },
"mime": { "type": "string" },
"size": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"disposition": { "type": "string", "enum": [ "attachment", "inline" ] },
"contentId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"downloadUrl": { "type": "string" }
},
"required": [
"id",
"position",
"filename",
"mime",
"size",
"disposition",
"contentId",
"downloadUrl"
],
"additionalProperties": false
}
}
},
"required": [
"id",
"mailboxId",
"from",
"subject",
"snippet",
"receivedAt",
"folderLabels",
"flags",
"signals",
"hasAttachments",
"threadId",
"classification",
"bodyText",
"bodyHtmlSafe",
"hasRemoteImages",
"bodyComplete",
"headersSubset",
"attachments"
],
"additionalProperties": false
}401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Codes d’erreur — request.not_found. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
GET /api/v1/messages/{id}/attachments/{position}
Télécharger une pièce jointe
Les octets bruts de la pièce à ce rang MIME, servis en téléchargement (Content-Disposition: attachment, nosniff, no-store). Les types actifs (HTML, SVG, scripts) sont forcés en application/octet-stream. Hors périmètre, rang inexistant ou objet purgé : un seul et même 404.
Accès — Session de membre ou clé d’API portant messages:read.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string (uuid) | oui |
position | chemin | integer | oui |
Réponses
200 — Le fichier.
Type de contenu : application/octet-stream
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Codes d’erreur — request.not_found. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
GET /api/v1/messages/{id}/journal
Le « pourquoi » d’un message
L’entrée de journal d’un message et les exécutions qu’il a lancées.
Accès — Session de membre ou clé d’API portant messages:read.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string (uuid) | oui |
Réponses
200 — L’entrée et ses exécutions.
| Champ | Type | Requis |
|---|---|---|
entry | object | null | oui |
executions | object[] | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"entry": {
"anyOf": [
{
"type": "object",
"properties": {
"id": { "type": "string" },
"outcome": {
"type": "string",
"enum": [
"excluded_org",
"excluded_member",
"guardrail",
"unmatched",
"dispatched"
]
},
"ruleRef": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"createdAt": { "type": "string" }
},
"required": [ "id", "outcome", "ruleRef", "createdAt" ],
"additionalProperties": false
},
{ "type": "null" }
]
},
"executions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"workflowId": { "type": "string" },
"workflowName": { "type": "string" },
"status": {
"type": "string",
"enum": [
"queued",
"running",
"waiting",
"succeeded",
"failed",
"cancelled"
]
},
"simulated": { "type": "boolean" },
"createdAt": { "type": "string" },
"finishedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [
"id",
"workflowId",
"workflowName",
"status",
"simulated",
"createdAt",
"finishedAt"
],
"additionalProperties": false
}
}
},
"required": [ "entry", "executions" ],
"additionalProperties": false
}401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Codes d’erreur — request.not_found. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
POST /api/v1/messages/send
Envoyer un message
Compose et enfile un message depuis une des boîtes du membre. Rien ne part de manière synchrone : la réponse porte l’opId de l’opération sortante et le miroir ramène l’état réel au delta suivant. clientToken est obligatoire et déduplique : un rejeu rend 202 { duplicate: true } avec la même opId. Les pièces jointes sont des références téléversées auparavant. Soumis au kill switch d’envoi (403) et au débit par boîte (429, avec Retry-After et retryAfterMs).
Accès — Session de membre ou clé d’API portant messages:write.
Corps de la requête (application/json)
| Champ | Type | Requis |
|---|---|---|
mailboxId | string | oui |
to | string (email)[] | oui |
cc | string (email)[] | non |
bcc | string (email)[] | non |
subject | string | oui |
bodyText | string | oui |
bodyHtml | string | non |
replyToMessageId | string | non |
forwardOfMessageId | string | non |
includeOriginalAttachments | boolean | non |
quoteOriginal | boolean | non |
attachments | object[] | non |
clientToken | string | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"mailboxId": { "type": "string", "minLength": 1 },
"to": {
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"maxLength": 320,
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
}
},
"cc": {
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"maxLength": 320,
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
}
},
"bcc": {
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"maxLength": 320,
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
}
},
"subject": { "type": "string", "maxLength": 512 },
"bodyText": { "type": "string", "maxLength": 200000 },
"bodyHtml": { "type": "string", "maxLength": 500000 },
"replyToMessageId": { "type": "string", "minLength": 1 },
"forwardOfMessageId": { "type": "string", "minLength": 1 },
"includeOriginalAttachments": { "type": "boolean" },
"quoteOriginal": { "type": "boolean" },
"attachments": {
"maxItems": 20,
"type": "array",
"items": {
"type": "object",
"properties": {
"attachmentId": {
"type": "string",
"minLength": 8,
"maxLength": 128,
"pattern": "^[A-Za-z0-9._-]+$"
}
},
"required": [ "attachmentId" ]
}
},
"clientToken": {
"type": "string",
"minLength": 8,
"maxLength": 128,
"pattern": "^[A-Za-z0-9._:-]+$"
}
},
"required": [ "mailboxId", "to", "subject", "bodyText", "clientToken" ]
}Réponses
202 — Enfilé.
| Champ | Type | Requis |
|---|---|---|
opId | string | oui |
kind | "send" | "draft" | oui |
duplicate | boolean | oui |
threadId | string | null | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"opId": { "type": "string" },
"kind": { "type": "string", "enum": [ "send", "draft" ] },
"duplicate": { "type": "boolean" },
"threadId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }
},
"required": [ "opId", "kind", "duplicate", "threadId" ],
"additionalProperties": false
}400 — La requête ne respecte pas son schéma.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Cette opération accepte un en-tête Idempotency-Key : rejouer la même requête avec la même clé rend la réponse d’origine au lieu d’agir deux fois. Voir Idempotence.
Codes d’erreur — webmail.bad_request, webmail.mailbox_not_found, webmail.message_not_found, webmail.attachment_not_found, webmail.message_too_large, webmail.sending_disabled, webmail.rate_limited. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
Exemple de requête
json
{
"mailboxId": "0192f1c2-3b4d-7e8f-9a0b-1c2d3e4f5a6b",
"to": [ "bob@example.test" ],
"subject": "Quote #1042",
"bodyText": "Hello Bob,\n\nPlease find the quote attached.\n\nAlice",
"attachments": [ { "attachmentId": "0192f1c2-0000-7000-8000-00000000a7a7" } ],
"clientToken": "b2c7e4a0-9f3d-4c1e-8a6b-5d2f1e0c9b8a"
}Exemple de réponse (202)
json
{
"opId": "0192f1c2-0000-7000-8000-0000000000aa",
"kind": "send",
"duplicate": false,
"threadId": null
}POST /api/v1/messages/drafts
Créer un brouillon
Le même corps que /send, enregistré en brouillon chez le fournisseur. Ni kill switch ni débit : un brouillon ne part pas. Un clientToken rejoué est un doublon, pas une réécriture — PUT réécrit.
Accès — Session de membre ou clé d’API portant messages:write.
Corps de la requête (application/json)
| Champ | Type | Requis |
|---|---|---|
mailboxId | string | oui |
to | string (email)[] | oui |
cc | string (email)[] | non |
bcc | string (email)[] | non |
subject | string | oui |
bodyText | string | oui |
bodyHtml | string | non |
replyToMessageId | string | non |
forwardOfMessageId | string | non |
includeOriginalAttachments | boolean | non |
quoteOriginal | boolean | non |
attachments | object[] | non |
clientToken | string | oui |
Même schéma que POST /api/v1/messages/send.
Réponses
202 — Enfilé.
| Champ | Type | Requis |
|---|---|---|
opId | string | oui |
kind | "send" | "draft" | oui |
duplicate | boolean | oui |
threadId | string | null | oui |
Même schéma que POST /api/v1/messages/send.
400 — La requête ne respecte pas son schéma.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Cette opération accepte un en-tête Idempotency-Key : rejouer la même requête avec la même clé rend la réponse d’origine au lieu d’agir deux fois. Voir Idempotence.
Codes d’erreur — webmail.bad_request, webmail.mailbox_not_found, webmail.message_not_found, webmail.attachment_not_found, webmail.message_too_large. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
PUT /api/v1/messages/drafts
Enregistrer un brouillon (autosave)
Réécrit le brouillon identifié par clientToken : le contenu déjà enregistré sous ce jeton est remplacé, donc une session de composition produit UN brouillon quel que soit le nombre de sauvegardes. savedAt est l’heure de cette sauvegarde. Ni kill switch ni débit.
Accès — Session de membre ou clé d’API portant messages:write.
Corps de la requête (application/json)
| Champ | Type | Requis |
|---|---|---|
mailboxId | string | oui |
to | string (email)[] | oui |
cc | string (email)[] | non |
bcc | string (email)[] | non |
subject | string | oui |
bodyText | string | oui |
bodyHtml | string | non |
replyToMessageId | string | non |
forwardOfMessageId | string | non |
includeOriginalAttachments | boolean | non |
quoteOriginal | boolean | non |
attachments | object[] | non |
clientToken | string | oui |
Même schéma que POST /api/v1/messages/send.
Réponses
202 — Enfilé.
| Champ | Type | Requis |
|---|---|---|
opId | string | oui |
kind | "send" | "draft" | oui |
duplicate | boolean | oui |
threadId | string | null | oui |
savedAt | string | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"opId": { "type": "string" },
"kind": { "type": "string", "enum": [ "send", "draft" ] },
"duplicate": { "type": "boolean" },
"threadId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] },
"savedAt": { "type": "string" }
},
"required": [ "opId", "kind", "duplicate", "threadId", "savedAt" ],
"additionalProperties": false
}400 — La requête ne respecte pas son schéma.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Codes d’erreur — webmail.bad_request, webmail.mailbox_not_found, webmail.message_not_found, webmail.attachment_not_found, webmail.message_too_large. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
POST /api/v1/messages/attachments
Téléverser une pièce jointe
Un fichier par requête, en multipart, avant de composer : la réponse donne l’attachmentId à référencer dans attachments. Rend ce que l’instance a constaté (nom nettoyé, type normalisé, taille mesurée). Au-delà de 25 Mo, 413 ; exécutables et scripts, 400.
Accès — Session de membre ou clé d’API portant messages:write.
Corps de la requête (multipart/form-data)
| Champ | Type | Requis | Description |
|---|---|---|---|
file | string | oui | The file, as a binary multipart part. |
Schéma JSON
json
{
"type": "object",
"properties": {
"file": { "type": "string", "description": "The file, as a binary multipart part." }
},
"required": [ "file" ]
}Réponses
201 — La pièce enregistrée.
| Champ | Type | Requis |
|---|---|---|
attachmentId | string | oui |
filename | string | oui |
size | integer | oui |
mime | string | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"attachmentId": { "type": "string" },
"filename": { "type": "string" },
"size": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
"mime": { "type": "string" }
},
"required": [ "attachmentId", "filename", "size", "mime" ],
"additionalProperties": false
}400 — La requête ne respecte pas son schéma.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Cette opération accepte un en-tête Idempotency-Key : rejouer la même requête avec la même clé rend la réponse d’origine au lieu d’agir deux fois. Voir Idempotence.
Codes d’erreur — webmail.bad_request, webmail.attachment_too_large, webmail.attachment_rejected. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
POST /api/v1/messages/{id}/forward
Transférer un message
Un raccourci sur /send : les pièces d’origine sont re-référencées par l’instance (sans re-téléversement), l’objet reçoit Fwd:, la chaîne References est conservée sans In-Reply-To. Même kill switch et même débit qu’un envoi.
Accès — Session de membre ou clé d’API portant messages:write.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string | oui |
Corps de la requête (application/json)
| Champ | Type | Requis |
|---|---|---|
to | string (email)[] | oui |
cc | string (email)[] | non |
bcc | string (email)[] | non |
subject | string | non |
bodyText | string | oui |
bodyHtml | string | non |
includeOriginalAttachments | boolean | non |
quoteOriginal | boolean | non |
attachments | object[] | non |
asDraft | boolean | non |
clientToken | string | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"to": {
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"maxLength": 320,
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
}
},
"cc": {
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"maxLength": 320,
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
}
},
"bcc": {
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"maxLength": 320,
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
}
},
"subject": { "type": "string", "maxLength": 512 },
"bodyText": { "type": "string", "maxLength": 200000 },
"bodyHtml": { "type": "string", "maxLength": 500000 },
"includeOriginalAttachments": { "type": "boolean" },
"quoteOriginal": { "type": "boolean" },
"attachments": {
"maxItems": 20,
"type": "array",
"items": {
"type": "object",
"properties": {
"attachmentId": {
"type": "string",
"minLength": 8,
"maxLength": 128,
"pattern": "^[A-Za-z0-9._-]+$"
}
},
"required": [ "attachmentId" ]
}
},
"asDraft": { "type": "boolean" },
"clientToken": {
"type": "string",
"minLength": 8,
"maxLength": 128,
"pattern": "^[A-Za-z0-9._:-]+$"
}
},
"required": [ "to", "bodyText", "clientToken" ]
}Réponses
202 — Enfilé.
| Champ | Type | Requis |
|---|---|---|
opId | string | oui |
kind | "send" | "draft" | oui |
duplicate | boolean | oui |
threadId | string | null | oui |
Même schéma que POST /api/v1/messages/send.
400 — La requête ne respecte pas son schéma.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Cette opération accepte un en-tête Idempotency-Key : rejouer la même requête avec la même clé rend la réponse d’origine au lieu d’agir deux fois. Voir Idempotence.
Codes d’erreur — webmail.bad_request, webmail.mailbox_not_found, webmail.message_not_found, webmail.attachment_not_found, webmail.message_too_large, webmail.sending_disabled, webmail.rate_limited. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
POST /api/v1/messages/{id}/reply
Répondre à un message
Un raccourci sur /send : boîte, destinataires, objet et fil sont pré-résolus depuis l’original, puis exactement le même chemin qu’un envoi — aucune réponse ne contourne le kill switch ni le débit.
Accès — Session de membre ou clé d’API portant messages:write.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string | oui |
Corps de la requête (application/json)
| Champ | Type | Requis |
|---|---|---|
to | string (email)[] | non |
cc | string (email)[] | non |
bcc | string (email)[] | non |
subject | string | non |
bodyText | string | oui |
bodyHtml | string | non |
asDraft | boolean | non |
attachments | object[] | non |
clientToken | string | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"to": {
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"maxLength": 320,
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
}
},
"cc": {
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"maxLength": 320,
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
}
},
"bcc": {
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"maxLength": 320,
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
}
},
"subject": { "type": "string", "maxLength": 512 },
"bodyText": { "type": "string", "maxLength": 200000 },
"bodyHtml": { "type": "string", "maxLength": 500000 },
"asDraft": { "type": "boolean" },
"attachments": {
"maxItems": 20,
"type": "array",
"items": {
"type": "object",
"properties": {
"attachmentId": {
"type": "string",
"minLength": 8,
"maxLength": 128,
"pattern": "^[A-Za-z0-9._-]+$"
}
},
"required": [ "attachmentId" ]
}
},
"clientToken": {
"type": "string",
"minLength": 8,
"maxLength": 128,
"pattern": "^[A-Za-z0-9._:-]+$"
}
},
"required": [ "bodyText", "clientToken" ]
}Réponses
202 — Enfilé.
| Champ | Type | Requis |
|---|---|---|
opId | string | oui |
kind | "send" | "draft" | oui |
duplicate | boolean | oui |
threadId | string | null | oui |
Même schéma que POST /api/v1/messages/send.
400 — La requête ne respecte pas son schéma.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Cette opération accepte un en-tête Idempotency-Key : rejouer la même requête avec la même clé rend la réponse d’origine au lieu d’agir deux fois. Voir Idempotence.
Codes d’erreur — webmail.bad_request, webmail.mailbox_not_found, webmail.message_not_found, webmail.attachment_not_found, webmail.message_too_large, webmail.sending_disabled, webmail.rate_limited. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
POST /api/v1/messages/{id}/actions
Agir sur un message
Archiver, marquer lu ou non lu, suivre, classer, mettre à la corbeille… La réponse dit que l’opération est enregistrée, pas que l’état a changé : le miroir le ramène au delta suivant. Les gestes que le fournisseur ne sait pas faire (suppression définitive chez Gmail) sont refusés avant d’enfiler.
Accès — Session de membre ou clé d’API portant messages:write.
Paramètres
| Nom | Où | Type | Requis |
|---|---|---|---|
id | chemin | string | oui |
Corps de la requête (application/json)
| Champ | Type | Requis |
|---|---|---|
action | string (enum) | oui |
labels | object | non |
clientToken | string | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"markRead",
"markUnread",
"flag",
"unflag",
"archive",
"unarchive",
"trash",
"restore",
"spam",
"notSpam",
"deletePermanently",
"move"
]
},
"labels": {
"type": "object",
"properties": {
"add": {
"maxItems": 20,
"type": "array",
"items": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"remove": {
"maxItems": 20,
"type": "array",
"items": { "type": "string", "minLength": 1, "maxLength": 200 }
}
}
},
"clientToken": {
"type": "string",
"minLength": 8,
"maxLength": 128,
"pattern": "^[A-Za-z0-9._:-]+$"
}
},
"required": [ "action", "clientToken" ]
}Réponses
202 — Les opérations enfilées.
| Champ | Type | Requis |
|---|---|---|
ops | object[] | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"ops": {
"type": "array",
"items": {
"type": "object",
"properties": {
"messageId": { "type": "string" },
"opId": { "type": "string" },
"duplicate": { "type": "boolean" }
},
"required": [ "messageId", "opId", "duplicate" ],
"additionalProperties": false
}
}
},
"required": [ "ops" ],
"additionalProperties": false
}400 — La requête ne respecte pas son schéma.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Cette opération accepte un en-tête Idempotency-Key : rejouer la même requête avec la même clé rend la réponse d’origine au lieu d’agir deux fois. Voir Idempotence.
Codes d’erreur — webmail.bad_request, webmail.message_not_found, webmail.unsupported_action. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.
POST /api/v1/messages/actions
Agir sur plusieurs messages
La même action sur au plus 100 messages, tout ou rien sur le périmètre : un seul identifiant hors des boîtes du membre rend 404 et rien n’est enfilé.
Accès — Session de membre ou clé d’API portant messages:write.
Corps de la requête (application/json)
| Champ | Type | Requis |
|---|---|---|
messageIds | string[] | oui |
action | string (enum) | oui |
labels | object | non |
clientToken | string | oui |
Schéma JSON
json
{
"type": "object",
"properties": {
"messageIds": {
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"action": {
"type": "string",
"enum": [
"markRead",
"markUnread",
"flag",
"unflag",
"archive",
"unarchive",
"trash",
"restore",
"spam",
"notSpam",
"deletePermanently",
"move"
]
},
"labels": {
"type": "object",
"properties": {
"add": {
"maxItems": 20,
"type": "array",
"items": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"remove": {
"maxItems": 20,
"type": "array",
"items": { "type": "string", "minLength": 1, "maxLength": 200 }
}
}
},
"clientToken": {
"type": "string",
"minLength": 8,
"maxLength": 128,
"pattern": "^[A-Za-z0-9._:-]+$"
}
},
"required": [ "messageIds", "action", "clientToken" ]
}Réponses
202 — Les opérations enfilées.
| Champ | Type | Requis |
|---|---|---|
ops | object[] | oui |
Même schéma que POST /api/v1/messages/{id}/actions.
400 — La requête ne respecte pas son schéma.
401 — Aucune session ni clé d’API valide (auth.unauthenticated).
403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).
429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.
Cette opération accepte un en-tête Idempotency-Key : rejouer la même requête avec la même clé rend la réponse d’origine au lieu d’agir deux fois. Voir Idempotence.
Codes d’erreur — webmail.bad_request, webmail.message_not_found, webmail.unsupported_action. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.