थ्रेड
`threads.list`, `listAll`, `iterate`, `get`, `update`, `trash`, `snooze`, `unsnooze` और `listAttachments`।
पढ़ना
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)API थ्रेड को pageToken से पेज करता है। क्लाइंट उसे आपको nextCursor के रूप में देता है और cursor के रूप में वापस लेता है, हर दूसरी सूची की तरह, और listAll तथा iterate उसका पीछा आपके लिए करते हैं। यह अपारदर्शी है: जो दिया गया वही वापस भेजें और कभी खुद न बनाएँ।
व्यवस्थित करना
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_…')यहाँ हर backend पर पढ़े जाने की स्थिति खुद एक लेबल है, इसलिए वह लेबल सूचियों के साथ चलती है और दोनों सेट करने पर क्रम निश्चित रहता है। तीनों फ़ील्ड में से कम से कम एक होना चाहिए।
किसी संदेश पर attachment
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 base64 है, और जब संग्रहीत बाइट्स नहीं मिल पातीं तो खाली string, इसलिए decode करने से पहले उसकी लंबाई जाँचें। एन्क्रिप्टेड संदेश का ciphertext इसी सूची में है और किसी भी दूसरी फ़ाइल की तरह डाउनलोड होता है; PGP/MIME संस्करण वाला भाग और कोई detached signature नहीं हैं। उनकी id encryption.parts में रहती हैं, और बस इतना ही।
ऐसा संदेश जो एन्क्रिप्टेड आया
यह SDK न एन्क्रिप्ट करता है न डिक्रिप्ट: यह वह संदेश नहीं खोल सकता जिसे किसी और ने एन्क्रिप्ट किया, और न एन्क्रिप्टेड संदेश भेज सकता है। अगर send request कोई एन्क्रिप्शन चिह्न लिए आती है तो उसे अस्वीकार कर दिया जाता है, क्योंकि बिना key वाले क्लाइंट को ऐसा दावा करने का कोई हक नहीं। OpenEmail ऐप में बनी keys उसी ब्राउज़र में रहती हैं जिसने उन्हें बनाया और यहाँ तक पहुँचती ही नहीं, और जब वह ब्राउज़र कोई सीलबंद संदेश खोलता है तो plaintext उसी में रह जाता है, और यह कॉल जो संग्रहीत संदेश पढ़ता है वह अब भी ciphertext है। threads.get आपको जो देता है वह envelope है, पहचाना हुआ। PGP- या S/MIME-लिपटा आया संदेश एक encryption object लिए चलता है, ताकि खाली decodedBody अकेली चीज़ न रह जाए जो आपको थमाई गई हो, और MessageResource पर encryption ही इकलौता फ़ील्ड है जिसका असली type है, क्योंकि यही वह है जिसकी अनुपस्थिति का अंदाज़ा लगाकर आप बच नहीं सकते।
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)}isSealed से शाखा बनाएँ, फ़ील्ड की मौजूदगी से कभी नहीं। पाँच में से दो प्रारूप, pgp-signed और smime-signed, ऐसी body बताते हैं जो एक detached signature के साथ साफ़ रूप में आई थी, इसलिए मौजूदगी पर रोक लगाना वह मेल छिपा देता है जिसे किसी को छिपाना ही नहीं था, और उपयोगकर्ता न उसे देख सकता है न समझा सकता है। isSealed ठीक इसीलिए शिप होता है: सर्वर सीलबंद समुच्चय को एक बार बताता है, और union से निकाली गई तीसरी प्रति वही प्रति है जो भटक जाती है।
अनुपस्थिति का अर्थ plaintext नहीं है। detection शिप होने से पहले संग्रहीत हर संदेश पर, और हर उस चीज़ पर जो मेलबॉक्स तक ऐसे रास्ते से पहुँची जहाँ detector कभी नहीं चला, encryption अनुपस्थित है। यह दर्ज करता है कि किसी ने देखा ही नहीं — यह तथ्य हमारी coverage के बारे में है, मेल के बारे में नहीं, और इसे कुछ भी backfill नहीं करता।
ये बाकियों से कहाँ अलग हैं
ThreadResource.messagesकी हर प्रविष्टि एकMessageResourceहै, यानी ठीक एक नामित फ़ील्ड वालाRecord<string, unknown>। बाकी को type देना क्लाइंट का ऐसा normalisation दावा करना होता जो कोई करता ही नहीं, औरencryptionफिर भी नामित है क्योंकि जो क्लाइंट उस पर शाखा नहीं बना सकता वह सीलबंद संदेश को खाली संदेश की तरह पढ़ता है।- जिस request को ईमानदारी से पूरा नहीं किया जा सकता वह 422
capability_unsupportedहै, न कि ऐसा रिस्पॉन्स जो सही दिखे और चुपचाप गलत हो।
पैरामीटर: threads.list (ThreadListOptions)
folderstring- कौन-सा फ़ोल्डर सूचीबद्ध करना है। सर्वर इसका डिफ़ॉल्ट `inbox` रखता है, इसलिए इसे छोड़ देना सूची को सब कुछ तक चौड़ा नहीं करता बल्कि संकरा करता है। यह `query` खोज पर भी लागू होता है, जब तक query खुद `in:` से या `is:sent` जैसे फ़ोल्डर `is:` से किसी फ़ोल्डर का नाम न ले ले।
querystring- मेलबॉक्स की खोज वाक्यरचना। सादे शब्द सभी आने चाहिए, और हर एक ढीला मिलान करता है: case, उच्चारण-चिह्न और विभाजक अनदेखे किए जाते हैं और किसी लंबे शब्द का हिस्सा भी गिना जाता है, इसलिए `min` और `ben jamin` दोनों "Benjamin" ढूँढ लेते हैं। उद्धृत वाक्यांश case और उच्चारण-चिह्नों को छोड़कर जैसा लिखा है वैसा ही मिलाया जाता है, इसलिए `"ben jamin"` से "Ben-Jamin" नहीं मिलता, और जब खोजने को कुछ और बचा हो तो भरने वाले शब्द छोड़ दिए जाते हैं। `from:ada`, `label:Invoices`, `is:unread`, `has:pdf`, `before:2026/01/31` और `older_than:1y` जैसे ऑपरेटरों से संकरा करें, और उन्हें `OR`, कोष्ठकों तथा आगे लगे `-` से जोड़ें; जो मान खोज इस्तेमाल नहीं कर सकती वह संकरा करने के बजाय अनदेखा कर दिया जाता है। शब्द और `from:`, `to:`, `cc:`, `subject:` तथा `body:` ऑपरेटर नवीनतम संदेश का प्रेषक, प्राप्तकर्ता, subject और markup हटाकर उसकी body के पहले 4,000 वर्ण पढ़ते हैं, जबकि `filename:` और `has:` पूरी बातचीत का हर attachment पढ़ते हैं और लेबल तथा फ़ोल्डर पूरी बातचीत पढ़ते हैं। यह उसी index को संकरा करता है जिसे बिना छाने वाली सूची पढ़ती है। सीलबंद संदेश कोई body टेक्स्ट संग्रहीत नहीं करते, इसलिए केवल उनका प्रेषक, प्राप्तकर्ता और subject ही मिलान कर सकते हैं।
labelIdsstring | string[]- सूची को केवल इन लेबल वाले थ्रेड तक सीमित करें। endpoint अल्पविराम से अलग की गई string लेता है और क्लाइंट array को आपके लिए एक में जोड़ देता है; आप कितने नाम लें, इसकी कोई सीमा नहीं।
limitnumber- कितने थ्रेड लौटाने हैं, 1 से 100 तक। छोड़ने पर handler 25 इस्तेमाल करता है। डिफ़ॉल्ट schema में नहीं handler में रहता है, इसलिए अनुपस्थित मान और स्पष्ट 25 एक जैसा व्यवहार करते हैं।
cursorstring- पिछले पेज का `nextCursor`, हूबहू वापस भेजा गया। यह API का `pageToken` ही है, बस उसी नाम से जो हर दूसरी सूची इस्तेमाल करती है, और यह अपारदर्शी है, इसलिए इसे कभी न बनाएँ न संपादित करें।
रिस्पॉन्स: Page<ThreadSummaryResource>
itemsThreadSummaryResource[]- इस पेज के हर थ्रेड के लिए एक प्रविष्टि, API के `data` envelope से बाहर उठाई हुई। हर प्रविष्टि केवल एक object चिह्न और एक id है। सूची में कोई subject, स्निपेट, प्रतिभागी या लेबल नहीं होते, इसलिए इससे ज़्यादा कुछ चाहिए तो जिन थ्रेड पर चाहिए उन पर `threads.get` कॉल करना होगा।
items[].idstring- थ्रेड की id, जिसे बिना बदले `threads.get`, `threads.update` और बाकी को देना है। पंक्ति चाहे छनी हुई सूची से आई हो या `query` खोज से, id वही रहती है।
hasMoreboolean- क्या आगे कोई पेज है, जो `nextCursor` से निकाला जाता है जहाँ API इसे नहीं बताता।
nextCursorstring | null- API का `nextPageToken`, जिसे अगले पेज के लिए `cursor` के रूप में वापस भेजना है, या null जब आगे कोई पेज नहीं। खाली token null पर normalise कर दिया जाता है, इसलिए falsy जाँच और null जाँच सहमत रहती हैं।