Converses
`threads.list`, `listAll`, `iterate`, `get`, `update`, `trash`, `snooze`, `unsnooze` i `listAttachments`.
Lectura
const page = await openemail.threads.list({ folder: 'inbox', query: 'from:ada', labelIds: ['INBOX', 'IMPORTANT'], limit: 25,}) const next = page.nextCursor ? await openemail.threads.list({ folder: 'inbox', cursor: page.nextCursor }) : null const thread = await openemail.threads.get('thread_…')console.log(thread.messageCount, thread.hasUnread, thread.totalReplies)L'API pagina les converses amb un pageToken. El client te'l lliura com a nextCursor i el recupera com a cursor, igual que a totes les altres llistes, i listAll i iterate el segueixen per tu. És opac: torna a passar el que t'han donat i no en construeixis mai cap.
Organització
await openemail.threads.update('thread_…', { read: true, addLabelIds: ['Done'], removeLabelIds: ['INBOX'],}) await openemail.threads.trash('thread_…')await openemail.threads.snooze('thread_…', new Date(Date.now() + 86_400_000))await openemail.threads.unsnooze('thread_…')L'estat de lectura ÉS una etiqueta a tots els backends d'aquí, de manera que viatja amb les llistes d'etiquetes i l'ordre és determinista quan estableixes tots dos. Com a mínim un dels tres camps hi ha de ser present.
Adjunts d'un missatge
const files = await openemail.threads.listAttachments('thread_…', 'message_…') for (const file of files) { console.log(file.filename, file.contentType, file.size) if (file.content) await save(file.filename, Buffer.from(file.content, 'base64'))}content és base64, i una cadena buida quan no s'han pogut trobar els bytes desats, així que comprova'n la longitud abans de descodificar. El text xifrat d'un missatge xifrat SÍ que és en aquesta llista i es baixa com qualsevol altre fitxer; la part de versió PGP/MIME i qualsevol signatura separada, no. Conserven els seus ids a encryption.parts i res més.
Un missatge que va arribar xifrat
Aquest SDK ni xifra ni desxifra: no pot obrir un missatge que ha xifrat algú altre, ni pot enviar-ne un de xifrat. La petició d'enviament es rebutja si porta un marcador de xifratge, perquè un client sense clau no té cap dret a afirmar-ne una. Les claus generades a l'aplicació OpenEmail viuen al navegador que les va crear i no arriben enlloc d'aquí, i quan aquell navegador obre un missatge segellat el text en clar es queda allà, i el missatge desat que llegeix aquesta crida continua sent text xifrat. El que et dona threads.get és el sobre, reconegut. Un missatge que va arribar embolcallat amb PGP o S/MIME porta un objecte encryption, de manera que un decodedBody buit deixa de ser l'única cosa que reps, i encryption és l'únic camp de MessageResource amb un tipus real, perquè és aquell l'absència del qual no pots sobreviure endevinant.
import { isSealed, openemail } from '@openemail/sdk' const thread = await openemail.threads.get('thread_…') for (const message of thread.messages) { if (!message.encryption) continue if (!isSealed(message)) continue console.warn('cannot read this one:', message.encryption.format)}Ramifica amb isSealed, mai segons la presència del camp. Dos dels cinc formats, pgp-signed i smime-signed, descriuen un cos que va arribar EN CLAR al costat d'una signatura separada, de manera que condicionar-ho a la presència amaga correu que ningú no necessitava amagar, i l'usuari no el pot veure ni explicar. isSealed s'inclou exactament per aquest motiu: el servidor declara el conjunt segellat un sol cop, i una tercera còpia escrita a partir de la unió és la còpia que acaba desviant-se.
L'absència no vol dir text en clar. encryption falta a tots els missatges desats abans que la detecció es publiqués, i a tot allò que va arribar a la bústia per una via on el detector no es va executar mai. Registra que ningú no ho va mirar, un fet sobre la nostra cobertura i no sobre el correu, i res no el reomple retroactivament.
En què es diferencien de la resta
- Cada entrada de
ThreadResource.messagesés unMessageResource, unRecord<string, unknown>amb exactament un camp amb nom. Tipar-ne la resta seria que el client afirmés una normalització que ningú no fa, iencryptionhi té nom igualment perquè un client que no hi pot ramificar llegeix un missatge segellat com si fos buit. - Una petició que no es pot servir fidelment dona un 422
capability_unsupported, no pas una resposta que sembla correcta i és silenciosament errònia.
Paràmetres: threads.list (ThreadListOptions)
folderstring- Quina carpeta s'ha de llistar. El servidor pren `inbox` per defecte, de manera que ometre-ho estreny el llistat en lloc d'eixamplar-lo a tot. També s'aplica a una cerca amb `query`, tret que la consulta mateixa anomeni una carpeta amb `in:` o amb un `is:` de carpeta com ara `is:sent`.
querystring- La sintaxi de cerca de la bústia. Totes les paraules simples hi han d'aparèixer, i cadascuna coincideix de manera laxa: s'ignoren majúscules, accents i separadors i val una part d'una paraula més llarga, de manera que tant `min` com `ben jamin` troben «Benjamin». Una frase entre cometes es compara tal com s'ha escrit tret de majúscules i accents, així que `"ben jamin"` no troba «Ben-Jamin», i les paraules de farciment es descarten quan queda alguna altra cosa per cercar. Estreny amb operadors com ara `from:ada`, `label:Invoices`, `is:unread`, `has:pdf`, `before:2026/01/31` i `older_than:1y`, i combina'ls amb `OR`, parèntesis i un `-` al davant; un valor que la cerca no pot fer servir s'ignora en lloc d'estrènyer. Les paraules i els operadors `from:`, `to:`, `cc:`, `subject:` i `body:` llegeixen el remitent, els destinataris i l'assumpte del missatge més recent i els primers 4.000 caràcters del seu cos sense marcatge, mentre que `filename:` i `has:` llegeixen tots els adjunts de la conversa sencera i les etiquetes i les carpetes llegeixen la conversa sencera. Estreny el mateix índex que llegeix el llistat sense filtrar. Els missatges segellats no desen cap text del cos, de manera que només hi poden coincidir el remitent, els destinataris i l'assumpte.
labelIdsstring | string[]- Restringeix el llistat a les converses que porten aquestes etiquetes. L'endpoint accepta una cadena separada per comes i el client hi uneix un array per tu; no hi ha cap límit de quantes en pots anomenar.
limitnumber- Quantes converses s'han de retornar, d'1 a 100. Si s'omet, el gestor fa servir 25. El valor per defecte viu al gestor i no a l'esquema, de manera que un valor absent i un 25 explícit es comporten igual.
cursorstring- El `nextCursor` de la pàgina anterior, tornat a passar literalment. És el `pageToken` de l'API amb el nom que fan servir totes les altres llistes, i és opac, així que no en construeixis ni n'editis mai cap.
Resposta: Page<ThreadSummaryResource>
itemsThreadSummaryResource[]- Una entrada per conversa en aquesta pàgina, extreta del sobre `data` de l'API. Cada entrada només és un marcador d'objecte i un id. El llistat no porta assumpte, fragment, participants ni etiquetes, de manera que qualsevol cosa més implica cridar `threads.get` a les converses que vulguis.
items[].idstring- L'id de la conversa, per passar-lo sense canvis a `threads.get`, `threads.update` i la resta. És el mateix id tant si la fila ve d'un llistat filtrat com d'una cerca amb `query`.
hasMoreboolean- Si hi ha una pàgina més, derivat de `nextCursor` allà on l'API no ho indica.
nextCursorstring | null- El `nextPageToken` de l'API, per tornar-lo a enviar com a `cursor` a la pàgina següent, o null quan no hi ha cap pàgina més. Un token buit es normalitza a null, de manera que una comprovació de valor fals i una de null coincideixen.