Ves a la documentació
API

Converses

Llegeix i organitza el correu.

GETapi.openemail.uk/threads

Executa qualsevol de les 7 crides d'aquesta pàgina contra el teu espai de treball, amb la teva pròpia clau.

Llistat

GET /threads?folder=inbox. Passar query cerca dins del mateix índex local. Totes les paraules simples hi han d'aparèixer, i cadascuna coincideix de manera laxa, ignorant majúscules, accents i separadors, de manera que min troba «Benjamin». Una frase entre cometes es compara tal com s'escriu, llevat de majúscules i accents, així que "ben jamin" no troba «Ben-Jamin». Les paraules buides com ara the o emails es descarten d'una llista de paraules simples quan queda alguna altra cosa per cercar. Operadors com from:, to:, subject:, label:, is:unread, has:pdf, after:2026/01/31 i newer_than:7d l'acoten, i OR, els parèntesis i un - inicial els combinen. Els destinataris es desen com una sola llista sense rols i mai no contenen un Bcc, de manera que cc: llegeix el mateix camp que to: i bcc: no coincideix amb res propi. from:me és el correu que has enviat, i to:me és el correu que porta una de les teves adreces, àlies inclosos, entre els seus destinataris o com a adreça a la qual es va lliurar.

Les paraules i els operadors from:, to:, cc:, subject: i body: llegeixen el missatge més nou de cada conversa: el remitent, els destinataris, l'assumpte i els primers 4.000 caràcters del cos. filename: i has: llegeixen tots els adjunts de tota la conversa, i label:, in: i is: llegeixen tota la conversa. folder continua aplicant-se llevat que la consulta n'anomeni una amb in:, o amb un is: que sigui una carpeta com ara is:sent, i in:anywhere cerca a totes les carpetes, tant sol com al costat d'altres termes. El llistat d'esborranys és l'excepció i es queda als esborranys digui el que digui la consulta.

Un valor que la cerca no pot fer servir s'ignora en lloc d'acotar, de manera que una errada en un valor amplia el resultat en comptes de buidar-lo: category:, larger:, smaller:, size:, messagesize:, list:, rfc822msgid:, received:, sent:, les paraules de categoria com ara is:promotions, una paraula de has: que no anomeni cap mena d'adjunt, un importance: que no sigui high ni low, una data il·legible i una durada amb una unitat que no sigui h, d, w, m o y. Un nom d'operador que no coneix, project: per exemple, es cerca com a text pla. Les dates llegeixen l'activitat més recent de la conversa, en UTC, amb after: incloent-hi el dia que anomena i before: excloent-lo; escriu-la com a YYYY/MM/DD, YYYY-MM-DD, YYYYMMDD, un any tot sol, o segons o mil·lisegons d'epoch.

nextPageToken és opac. Torna exactament el que se t'ha donat; no en construeixis ni n'editis mai cap. La seva forma no forma part del contracte.

Recuperació

GET /threads/{id} retorna tots els missatges de la conversa, no només el més recent, juntament amb les seves etiquetes i si hi ha res sense llegir.

Missatges que han arribat xifrats

Aquesta API ni xifra ni desxifra. No pot obrir un missatge que ha xifrat algú altre, i no en pot enviar cap de xifrat. Una sol·licitud que porti un marcador de xifratge es rebutja amb un 422, perquè les úniques superfícies que en poden posar un són les que tenen les claus, i cap client de l'API no en té cap. El que sí que fa és RECONÈIXER un sobre segellat a l'entrada, a partir del Content-Type de primer nivell i res més, i després dir-ho al missatge.

Ara OpenEmail sí que té claus, i val la pena ser exactes sobre quina meitat i on. El propietari d'una bústia genera una identitat OpenPGP al navegador i publica la clau PÚBLICA en un directori que altres remitents d'OpenEmail amb la sessió iniciada poden resoldre. La meitat privada es crea en aquell navegador, no s'envia mai aquí i no es pot recuperar mai, de manera que res d'aquesta API no pot desxifrar res, i cap petició de suport, citació judicial ni còpia de seguretat nostra no produeix una clau que ho pogués fer. L'aplicació web ja pot OBRIR un missatge PGP/MIME o inline-PGP quan la clau és al navegador de qui llegeix, però aquest desxifratge passa a la pestanya i el text en clar no es torna a escriure mai: el missatge desat continua sent text xifrat, i cap resposta d'aquesta API no porta mai el text obert. L'aplicació ja pot segellar un missatge nou al navegador i enviar-lo: el redactor xifra amb les claus publicades dels destinataris i el correu surt com a PGP/MIME. Aquesta API encara no pot segellar res, de manera que el camp de més avall descriu tant el correu que ha xifrat algú altre com el correu segellat en una pestanya d'OpenEmail.

Això mereix un camp pel que era l'alternativa. Un missatge segellat no desa cap cos llegible, així que decodedBody torna com a "", els mateixos bytes que un missatge que realment no tenia contingut. encryption és el que et permet distingir-los abans d'actuar sobre cap dels dos, i és una afirmació sobre el sobre i no pas una verificació: veure que un missatge està segellat no és el mateix que haver-lo obert.

Resposta
{    "object": "thread",    "id": "thread_2f9b…",    "messages": [      {        "id": "msg_7c41…",        "subject": "Q3 numbers",        "decodedBody": "",        "encryption": {          "format": "pgp-mime",          "detectedAt": "2026-08-30T09:14:22.117Z",          "rawRetained": false,          "parts": [            { "index": 0, "attachmentId": "msg_7c41…-0", "role": "version" },            { "index": 1, "attachmentId": "msg_7c41…-1", "role": "ciphertext" }          ]        }      }    ]  }

encryption

format'pgp-mime' | 'pgp-signed' | 'pgp-inline' | 'smime-encrypted' | 'smime-signed'
Quin sobre ha arribat. Es llegeix del `Content-Type` de primer nivell (el seu paràmetre `protocol` per a PGP, el seu `smime-type` per a S/MIME) o, per a `pgp-inline`, d'un cos que comença amb la capçalera d'armor de PGP. Una part `pkcs7-mime` que no porti cap `smime-type` es llegeix com a `smime-encrypted`, que és el que en fa l'RFC 8551 per defecte.
detectedAtstring
ISO 8601, quan es va executar el detector, que és quan el missatge es va ingerir aquí. No diu res sobre quan es va xifrar el missatge, ni qui ho va fer.
rawRetainedboolean
Si s'han conservat els bytes RFC822 originals, de manera que el missatge es pugui retornar sencer. Fals en tots els missatges d'avui dia, ja que aquí encara no hi ha res que retingui el correu en brut. És a la resposta ara mateix perquè el dia que això canviï no sigui també el dia en què s'hagi de tornar a migrar cada missatge desat.
partsobject[]
Les parts del sobre que fa servir aquest format. Hi és sempre que hi hagi `encryption`, i és buit quan no n'hi ha cap per anomenar: `pgp-inline` no té cap part separada, perquè el seu armor ÉS el cos i arriba a `decodedBody`.
parts[].indexnumber
Quina part MIME del missatge original era aquesta, comptada sobre les parts tal com van arribar i no sobre `attachments`. Les dues llistes difereixen, que és tota la raó per la qual això es registra.
parts[].attachmentIdstring
L'id que aquesta part porta a `attachments`, quan hi apareix: l'id del missatge amb l'índex de la part afegit al final. La part `ciphertext` es llista i es descarrega com qualsevol altre fitxer; `version` i `signature` queden fora de la llista, de manera que els seus ids només correlacionen les dues vistes i res més. L'endpoint d'adjunts no els retornarà.
parts[].role'version' | 'ciphertext' | 'signature'
`version` és la part de control de PGP/MIME, `ciphertext` és el missatge i `signature` és una signatura separada. Només val la pena baixar `ciphertext`; les altres dues són mobiliari del protocol que abans es dibuixava com a adjunts escombraria i que ara ja no.
formatQuè ha arribatCos
pgp-mimeUn sobre PGP/MIME: multipart/encrypted amb protocol=application/pgp-encrypted.Segellat
pgp-inlineArmor dins del mateix cos. Només es llegeix del text del cos, de manera que una resposta que només cita un bloc amb armor no es confon amb un missatge xifrat.Segellat
smime-encryptedUna part pkcs7-mime d'S/MIME amb smime-type=enveloped-data, o una que no tingui cap smime-type.Segellat
pgp-signedUna signatura PGP separada al costat del missatge: multipart/signed amb protocol=application/pgp-signature.Llegible
smime-signedUna signatura S/MIME separada: un protocol pkcs7-signature, o smime-type=signed-data.Llegible

Signat no vol dir segellat, i ramificar segons la presència d'encryption en comptes de segons format ho entén exactament al revés. Una signatura és una afirmació sobre qui va escriure el missatge, no pas un embolcall al seu voltant: el cos d'un missatge signat és en clar i es llegeix com qualsevol altre. Tracta pgp-mime, pgp-inline i smime-encrypted com a il·legibles, i els dos formats signats com a correu ordinari.

Què canvia en un missatge segellat

Només els tres formats segellats canvien res, i el canvi passa en la ingesta, no en aquesta resposta. Tot allò que hauria llegit el cos es fa enrere, en comptes de llegir text xifrat i informar d'un resultat que no hauria pogut obtenir:

  • La cerca dins del cos. El missatge s'indexa amb un fragment de cos buit, de manera que encara es troba per remitent, assumpte, adreça i etiqueta, però no per res del seu interior.
  • La passada sobre el cos del puntuador de phishing. El veredicte continua arribant i diu què no ha pogut fer: risk.signals porta body-encrypted i risk.aiChecked és fals.
  • La comprovació d'autoria per IA, que es fa enrere en comptes d'endevinar: aiWritten.level és unknown i aiWritten.skipped és encrypted.
  • Les condicions sobre el cos a les regles. Les condicions sobre el sobre i les capçaleres s'executen exactament igual que abans; una regla que preguntava pel cos es registra com a no avaluada en comptes de comptar-se com a no coincidència, perquè «no ha coincidit» i «no s'ha pogut llegir» són respostes diferents.
  • La importació d'invitacions de calendari. La invitació és dins del text xifrat, i construir un esdeveniment a partir del sobre posaria una entrada equivocada en un calendari real.
  • Els resums i els embeddings de la conversa, per a tota la conversa. Amb una sola resposta segellada n'hi ha prou. Un resum és la lectura que un model fa del text en clar, desada com a metadada en clar, que és l'únic punt d'aquest pipeline on un cos es filtraria cap a un magatzem que ningú no considera un cos.

Tot allò que no necessita el cos queda intacte:

  • DMARC, DKIM i SPF. Es llegeixen d'Authentication-Results, que el text xifrat no amaga, de manera que un missatge xifrat continua rebent un veredicte d'autenticació real i no pas cap.
  • L'agrupació en converses, la classificació com a brossa i la llista de bloqueig: tot això és feina de sobre i capçaleres.
  • Els adjunts. La part de text xifrat es queda a attachments, amb el nom encrypted-message.asc quan arriba sense nom, i es descarrega per l'endpoint de més avall. És exactament el que el lector de la mateixa aplicació web baixa i desxifra al navegador; per a un client de l'API, que no té cap clau, aquesta descàrrega continua sent l'única manera de llegir el correu. Obre'l amb un client que en tingui una.
  • Un missatge signat no perd res d'això. Totes les comprovacions anteriors continuen executant-se sobre ell, i no se'n reté res, que és per això que la llista de formats segellats en té tres i no pas cinc.

L'absència d'encryption no és una afirmació que hi hagi text en clar. Vol dir que ningú no ho ha mirat: el missatge és anterior a la detecció, o va arribar a la bústia per un camí que no executa el detector. Res no ho reomple retroactivament, de manera que un camp que diu «no ho hem comprovat» no s'ha de llegir mai com a «ho hem comprovat i no n'hi havia».

Marcatge i etiquetatge

PATCH /threads/{id} accepta read, addLabelIds i removeLabelIds. L'estat de llegit és una etiqueta a tots els backends que aquest producte admet, de manera que definir read i moure etiquetes en una sola crida manté l'ordre determinista.

PATCH
{ "read": true, "addLabelIds": ["USER_INVOICES"] }

Aquí TRASH i SNOOZED es rebutgen amb label_not_directly_settable. Cap dels dos estats no el porta només la seva etiqueta (enviar a la paperera també esborra les etiquetes de carpeta, i una posposició necessita una hora de retorn desada al costat), així que posar-los a mà deixa una conversa en un estat que l'aplicació no produeix mai i del qual no pot sortir. Fes servir els endpoints de més avall.

Paperera i posposició

EndpointQuè fa
POST /threads/{id}/trashMou a la paperera i esborra alhora INBOX, SPAM, SNOOZED i ARCHIVE.
POST /threads/{id}/snoozeCos { "wakeAt": "…" }. L'amaga i programa el seu retorn.
POST /threads/{id}/unsnoozeLa torna ara mateix i cancel·la el retorn programat.

Posposar escriu dues coses: l'etiqueta que amaga la conversa i l'entrada que la torna. Fer-ne una sense l'altra és exactament el motiu pel qual això són endpoints i no edicions d'etiquetes.

Adjunts

GET /threads/{id}/messages/{messageId}/attachments retorna cada adjunt amb filename, contentType, size i content en base64. content és una cadena buida quan els bytes desats no s'han pogut trobar, així que comprova'n la longitud abans de descodificar.

D'un sobre xifrat no hi és tot. El text xifrat sí (és el missatge, i descarregar-lo és l'única manera que un client de l'API té de llegir aquest correu), però la part de versió de PGP/MIME i qualsevol signatura separada queden fora de la llista, perquè es dibuixaven com a adjunts escombraria i qui fa la crida no en pot fer res. Totes dues conserven els seus ids a encryption.parts, que correlaciona les dues vistes; aquest endpoint no les retorna.