Threads
`threads.list`, `listAll`, `iterate`, `get`, `update`, `trash`, `snooze`, `unsnooze` en `listAttachments`.
Lezen
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)De API pagineert threads met een pageToken. De client geeft hem aan je door als nextCursor en neemt hem terug aan als cursor, net als bij elke andere lijst, en listAll en iterate volgen hem voor je. Hij is opaak: stuur terug wat je gekregen hebt en bouw er nooit zelf een.
Ordenen
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_…')De leesstatus IS hier op elke backend een label, dus die reist mee met de labellijsten en de volgorde is deterministisch wanneer je beide zet. Minstens één van de drie velden moet aanwezig zijn.
Bijlagen bij een bericht
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 is base64, en een lege string wanneer de opgeslagen bytes niet gevonden konden worden, dus controleer de lengte voordat je decodeert. De ciphertext van een versleuteld bericht STAAT in deze lijst en downloadt als elk ander bestand; het PGP/MIME-versiedeel en een eventuele losse handtekening niet. Die houden hun ids in encryption.parts en verder niets.
Een bericht dat versleuteld binnenkwam
Deze SDK versleutelt noch ontsleutelt: hij kan geen bericht openen dat iemand anders versleuteld heeft, en hij kan er geen versleuteld bericht mee versturen. Het verzoek om te versturen wordt geweigerd als het een encryptiemarkering meedraagt, want een client zonder sleutel heeft niets te beweren. Sleutels die in de OpenEmail-app gegenereerd zijn, leven in de browser die ze gemaakt heeft en bereiken hier niets, en wanneer die browser een verzegeld bericht opent, blijft de platte tekst daar, en het opgeslagen bericht dat deze aanroep leest is nog steeds ciphertext. Wat threads.get je geeft is de envelop, herkend. Een bericht dat in PGP- of S/MIME-verpakking binnenkwam draagt een encryption-object mee, zodat een lege decodedBody niet langer het enige is wat je in handen krijgt, en encryption is het enige veld op MessageResource met een echt type, omdat het het veld is waarvan je de afwezigheid niet ongestraft kunt raden.
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)}Vertak met isSealed, nooit op de aanwezigheid van het veld. Twee van de vijf formaten, pgp-signed en smime-signed, beschrijven een body die ONVERSLEUTELD binnenkwam naast een losse handtekening, dus afgaan op aanwezigheid verbergt mail die niemand hoefde te verbergen, en de gebruiker kan het niet zien en niet verklaren. isSealed bestaat precies daarom: de server stelt de verzegelde verzameling één keer vast, en een derde kopie die uit de union is overgeschreven is de kopie die gaat afwijken.
Afwezigheid betekent niet platte tekst. encryption ontbreekt op elk bericht dat opgeslagen is voordat de detectie live ging, en op alles wat de mailbox bereikte langs een pad waar de detector nooit gelopen heeft. Het legt vast dat niemand gekeken heeft, een feit over onze dekking en niet over de mail, en niets vult het achteraf aan.
Waarin deze afwijken van de rest
- Elk item in
ThreadResource.messagesis eenMessageResource, eenRecord<string, unknown>met precies één benoemd veld erop. De rest typeren zou betekenen dat de client een normalisatie beweert die niemand uitvoert, enencryptionis toch benoemd omdat een client die daar niet op kan vertakken een verzegeld bericht als een leeg bericht leest. - Een verzoek dat niet getrouw bediend kan worden is een 422
capability_unsupported, en geen respons die er goed uitziet en stilletjes fout is.
Parameters: threads.list (ThreadListOptions)
folderstring- Welke map je wilt opvragen. De server zet hem standaard op `inbox`, dus weglaten versmalt de lijst in plaats van hem tot alles te verbreden. Hij geldt ook voor een zoekopdracht met `query`, tenzij de query zelf een map noemt met `in:` of met een map-`is:` zoals `is:sent`.
querystring- De zoeksyntaxis van de mailbox. Losse woorden moeten allemaal voorkomen, en elk matcht losjes: hoofdletters, accenten en scheidingstekens worden genegeerd en een deel van een langer woord telt mee, dus `min` en `ben jamin` vinden allebei "Benjamin". Een zinsdeel tussen aanhalingstekens wordt gematcht zoals het geschreven is, afgezien van hoofdletters en accenten, dus `"ben jamin"` vindt "Ben-Jamin" niet, en stopwoorden vallen weg zodra er iets anders overblijft om op te zoeken. Versmal met operatoren zoals `from:ada`, `label:Invoices`, `is:unread`, `has:pdf`, `before:2026/01/31` en `older_than:1y`, en combineer ze met `OR`, haakjes en een `-` ervoor; een waarde die de zoekopdracht niet kan gebruiken wordt genegeerd in plaats van dat hij versmalt. Woorden en de operatoren `from:`, `to:`, `cc:`, `subject:` en `body:` lezen de afzender, de ontvangers, het onderwerp en de eerste 4.000 tekens van de body van het laatste bericht met de opmaak eruit gestript, terwijl `filename:` en `has:` elke bijlage van het hele gesprek lezen en labels en mappen het hele gesprek lezen. Het versmalt dezelfde index die de ongefilterde lijst leest. Verzegelde berichten slaan geen bodytekst op, dus alleen hun afzender, ontvangers en onderwerp kunnen matchen.
labelIdsstring | string[]- Beperk de lijst tot threads die deze labels dragen. Het endpoint neemt een door komma's gescheiden string aan en de client voegt een array voor je samen tot één string; er is geen limiet op hoeveel je er noemt.
limitnumber- Hoeveel threads teruggegeven worden, van 1 tot 100. Weggelaten gebruikt de handler 25. De standaardwaarde zit in de handler en niet in het schema, dus een ontbrekende waarde en een expliciete 25 gedragen zich hetzelfde.
cursorstring- De `nextCursor` van de vorige pagina, letterlijk teruggestuurd. Het is de `pageToken` van de API onder de naam die elke andere lijst gebruikt, en hij is opaak, dus construeer of bewerk er nooit een.
Respons: Page<ThreadSummaryResource>
itemsThreadSummaryResource[]- Eén item per thread op deze pagina, gelicht uit de `data`-envelop van de API. Elk item is niet meer dan een objectmarkering en een id. De lijst bevat geen onderwerp, snippet, deelnemers of labels, dus voor meer moet je `threads.get` aanroepen op de threads die je wilt.
items[].idstring- De id van de thread, om ongewijzigd door te geven aan `threads.get`, `threads.update` en de rest. Het is dezelfde id, of de rij nu uit een gefilterde lijst of uit een zoekopdracht met `query` komt.
hasMoreboolean- Of er nog een pagina is, afgeleid uit `nextCursor` waar de API het niet zelf vermeldt.
nextCursorstring | null- De `nextPageToken` van de API, terug te sturen als `cursor` voor de volgende pagina, of null wanneer er geen volgende pagina is. Een leeg token wordt genormaliseerd naar null, zodat een falsy-check en een null-check het eens zijn.