client.Threads
Jede Methode in diesem Namespace: ihre Signatur, ihre Parameter, was sie zurückgibt und ein Beispiel.
Methoden
Read, search, label, trash, snooze and mute conversations in the mailbox, read the inbox one tab at a time, and choose the tab the mail of a sender always goes to.
Threads.ListThreads.ListAllThreads.IterateThreads.GetThreads.UpdateThreads.TrashThreads.SnoozeThreads.UnsnoozeThreads.MuteThreads.UnmuteThreads.ListAttachmentsThreads.ListNotesThreads.CreateNoteThreads.UpdateNoteThreads.DeleteNoteThreads.ReorderNotesThreads.CountsThreads.SummaryThreads.ReplySuggestionsThreads.RestoreThreads.DeleteThreads.UnsubscribeThreads.GetEventThreads.ListSenderCategoriesThreads.SetSenderCategoryThreads.ClearSenderCategory
Threads.List
List one page of threads in a folder
List(ctx context.Context, opts ...openemail.RequestOption) (*openemail.Page, error)Returns one page of threads from the mailbox index, ordered by each thread's latest message with the newest first unless sort says otherwise. A row is only object and id, so call Get for the messages, labels and unread state.
sort, dateFrom, dateTo and fromContacts are the thread list's own controls: the four orders, a date range read against the newest message on each thread, and a filter to mail from saved contacts. Every order pages to the end, and a cursor carries on in the order it was handed out in, so send the same filters with it.
folder defaults to inbox and is matched against label ids after being upper cased, so sent, archive, spam, Trash, draft, snoozed, starred and unread all work, bin is read as Trash, and a user label id works as a folder too. A name that matches nothing returns an empty page rather than an error. labelIds narrows the folder further: a thread must carry the folder label and every id you pass. category keeps one inbox tab, primary, promotions, updates, social or forums, where primary is every thread in no other tab.
query takes the mailbox search syntax. Plain words must all appear, and each matches loosely: case, accents and separators are ignored and part of a longer word counts, so min finds "Benjamin". A quoted phrase is matched as written apart from case and accents, so "ben jamin" does not find "Ben-Jamin" while "quarterly invoice" finds "Quarterly invoice". When nothing matches exactly, close spellings are returned instead, so benjimin finds "Benjamin": a plain word, or the value of from:, to:, cc:, subject:, body:, filename: or label:, may differ from the start of a word by one typo when it has four to seven letters and by two when it has eight or more, while a quoted phrase, a word containing a digit, a shorter word and an excluded word still match exactly, and the pages that follow keep matching the same way. Filler words such as the, about or emails are dropped from a list of plain words when something else is left to search for, so emails from john searches for john alone. Operators such as from:, to:, subject:, label:, is:unread, has:pdf, after:2026/01/31 and newer_than:7d narrow it, and OR, parentheses and a leading - combine them. is:muted finds muted threads, is:waiting the threads with a reminder nobody has answered yet, and category:promotions one inbox tab in any folder. Recipients are stored as one list without roles and never hold a Bcc, so cc: reads the same field as to: and bcc: matches nothing of its own. from:me is mail you sent, and to:me is mail carrying one of your own addresses, aliases included, among its recipients or as the address it was delivered to.
With semantic: true the plain words of query match by meaning rather than spelling. Describe the mail in a few words, flight to Berlin or invoices I still owe, in any language, and the threads closest in meaning come back best match first, together with every thread the words match as text, which ranks above one that only means the same. A thread is kept only when it is clearly closer to the words than the rest of the mailbox, so a description nothing fits returns only the text matches. Operators and filters narrow it as usual, sort does not apply, and a query with no plain words is a text search whatever semantic says. Meaning is read from the whole conversation, newest messages first, so an earlier message counts too, and a workspace that turned search by meaning off in its settings gets a text search instead.
Words and the from:, to:, cc:, subject: and body: operators read only the newest message on each thread: its sender, its recipients, its subject and the first 4,000 characters of its body with markup stripped. filename: and has: read every attachment on the whole conversation, and label:, in: and is: read the whole conversation. A plain word also matches the name of any attachment on the conversation, whichever message carried it. A sealed message has no body text to match. The search stays inside folder unless the query names a folder itself, with in: or a folder is: such as is:sent, and in:anywhere searches every folder, on its own as well as beside other terms. A drafts listing is the exception and stays in drafts whatever the query names.
Dates read the newest activity on the thread, in UTC. after: includes the day it names and before: excludes it, and a date can be written YYYY/MM/DD, YYYY-MM-DD, YYYYMMDD, as a bare year, or as epoch seconds or milliseconds. A short date reads day first (16/09/2026), unless the second number cannot be a month (09/16/2026), and a number above 12 settles it either way. The API pages with an opaque pageToken, which the SDK hands back as NextCursor and accepts as openemail.WithCursor.
Parameter
openemail.WithFolderstringLabel the threads must carry, case insensitive. Defaults to
inbox, andbinis read asTrash.openemail.WithQuerystringMailbox search. Plain words must all appear and match loosely, a quoted phrase has to appear as written, filler words are dropped when something else is left to search for, and operators such as
from:ada,has:pdfandin:anywherenarrow it.openemail.WithLabelIDs...stringLabel ids a thread must all carry on top of
folder, matched exactly. An array is sent comma separated.openemail.WithSortstringnewest(the default),oldest,senderorsubject, the four orders of the thread list in the app.senderandsubjectare alphabetical, newest first within one sender or subject.openemail.WithDateFromtime.TimeKeeps threads whose newest message arrived at or after this instant. A
time.Time.openemail.WithDateTotime.TimeKeeps threads whose newest message arrived at or before this instant. Both ends are included, and
dateFromafterdateTois a 422.openemail.WithFromContactsboolWhen true, keeps only threads whose newest message came from a saved contact. A key limited to some addresses reads the contacts its owner saved.
openemail.WithSemanticboolWhen true, the plain words of
querymatch by meaning instead of spelling, in any language, and the closest threads come first along with every thread the words match as text. Operators and the other filters still apply andsortdoes not. Ignored when the workspace has search by meaning turned off.openemail.WithCategorystringKeeps only the threads sorted into this inbox tab:
primary,promotions,updates,socialorforums.primaryis every thread in no other tab. Inquery,category:promotionsfilters the same way in any folder.openemail.WithAddressstringKeeps only the threads delivered to this address, the address filter of the thread list. One the key does not reach returns nothing rather than failing.
openemail.WithLimitintThreads per page, a whole number from 1 to 100. Defaults to 25.
openemail.WithCursorstringThe
NextCursorof the previous page, passed back unchanged.openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
A *openemail.Page with Items, HasMore and NextCursor. Each item is a map with object set to thread and id.
Beispiel
page, err := client.Threads.List(ctx, openemail.WithFolder("inbox"), openemail.WithQuery("from:ada has:pdf"), openemail.WithLimit(50))if err != nil { return err} for _, thread := range page.Items { fmt.Println(thread.String("id"))} fmt.Println(page.HasMore, page.NextCursor)Hinweise
The server offers a cursor whenever a page comes back full, so
HasMorecan be true on what turns out to be the last page, and the next call then returns no items.Threads that arrived in the same instant are ordered by id, so a page boundary between two of them never skips or repeats one.
A thread that receives mail while you page moves ahead of the cursor and is not returned by later pages.
A value
querycannot use is ignored rather than narrowing, so a typo in a value widens the result instead of emptying it. That coverslarger:,smaller:,size:,messagesize:,list:,rfc822msgid:,received:andsent:, acategory:naming no inbox tab, ahas:word naming no kind of attachment, animportance:other thanhighorlow, an unreadable date and a duration whose unit is noth,d,w,mory. An operator name it does not know,project:for instance, is searched as plain text.A narrowed key only sees threads delivered to the addresses it covers, every address on a whole domain it holds included. A thread still has to carry the folder and every one of
labelIds, the same as for any other key.
Auch verfügbar über
- API
GET /threads- TypeScript
threads.list()- Python
threads.list()- Ruby
threads.list- PHP
threads->list- Java
threads().list- C#
Threads.ListAsync- CLI
openemail threads list
Threads.ListAll
Collect every thread in a folder into one slice
ListAll(ctx context.Context, opts ...openemail.RequestOption) ([]openemail.Object, error)Walks every page with the same filters as List and returns once the last page is in, so the whole result sits in memory at once. That suits a label view or a small folder. For a large inbox, Iterate lets you stop as soon as you have what you need.
Each request asks for openemail.WithLimit threads, 25 when you leave it out, so raising it to 100 needs a quarter of the round trips. Passing openemail.WithCursor starts the walk from that page instead of the first. The walk ends when HasMore is false, when the server stops offering a cursor, or when it repeats one.
A failure on any page fails the call and discards everything collected so far.
Parameter
openemail.WithFolderstringLabel the threads must carry, case insensitive. Defaults to
inbox.openemail.WithQuerystringMailbox search, as in
List. Plain words must all appear and match loosely, a quoted phrase has to appear as written, filler words are dropped when something else is left to search for, and operators such asfrom:ada,has:pdfandin:anywherenarrow it.openemail.WithLabelIDs...stringLabel ids a thread must all carry on top of
folder, matched exactly.openemail.WithSortstringnewest(the default),oldest,senderorsubject, the four orders of the thread list in the app.senderandsubjectare alphabetical, newest first within one sender or subject.openemail.WithDateFromtime.TimeKeeps threads whose newest message arrived at or after this instant. A
time.Time.openemail.WithDateTotime.TimeKeeps threads whose newest message arrived at or before this instant. Both ends are included, and
dateFromafterdateTois a 422.openemail.WithFromContactsboolWhen true, keeps only threads whose newest message came from a saved contact. A key limited to some addresses reads the contacts its owner saved.
openemail.WithSemanticboolWhen true, the plain words of
querymatch by meaning instead of spelling, in any language, and the closest threads come first along with every thread the words match as text. Operators and the other filters still apply andsortdoes not. Ignored when the workspace has search by meaning turned off.openemail.WithCategorystringKeeps only the threads sorted into this inbox tab:
primary,promotions,updates,socialorforums.primaryis every thread in no other tab.openemail.WithAddressstringKeeps only the threads delivered to this address, the address filter of the thread list. One the key does not reach returns nothing rather than failing.
openemail.WithLimitintPage size for each request, a whole number from 1 to 100. Defaults to 25.
openemail.WithCursorstringA
NextCursorto start the walk from instead of the first page.openemail.WithAPIKeystringOverrides the client's API key for every page of this walk.
Rückgabe
A []openemail.Object, every matching thread as a map with object set to thread and id, newest first.
Beispiel
snoozed, err := client.Threads.ListAll(ctx, openemail.WithFolder("snoozed"), openemail.WithLimit(100))if err != nil { return err} for _, thread := range snoozed { fmt.Println(thread.String("id"), thread.String("object"))}Hinweise
Each page is its own request with its own retries, so a network blip on page five does not restart the walk from page one.
Rows are ids only. Reading the threads afterwards is one
Getper id.
Auch verfügbar über
- API
GET /threads- TypeScript
threads.listAll()- Python
threads.list_all()- Ruby
threads.list_all- PHP
threads->listAll- Java
threads().listAll- C#
Threads.ListAllAsync
Threads.Iterate
Stream threads one at a time across pages
Iterate(ctx context.Context, opts ...openemail.RequestOption) *openemail.IteratorReturns an iterator that yields threads one by one and requests the next page only when the current one is used up. Nothing is fetched until the loop starts, and breaking out of it stops further requests, so this is the way to scan a large folder for the first match.
Filters behave as in List, and each request asks for openemail.WithLimit threads, 25 by default. The cursor marks a position in time rather than a row count, so trashing, archiving or relabelling threads inside the loop does not make the walk skip the ones after them. A thread that receives new mail during the walk moves ahead of the cursor and is not yielded again. With semantic: true the cursor counts places in the ranked list instead, so moving a thread out of the folder during the walk can shift the ones after it.
Parameter
openemail.WithFolderstringLabel the threads must carry, case insensitive. Defaults to
inbox.openemail.WithQuerystringMailbox search, as in
List. Plain words must all appear and match loosely, a quoted phrase has to appear as written, filler words are dropped when something else is left to search for, and operators such asfrom:ada,has:pdfandin:anywherenarrow it.openemail.WithLabelIDs...stringLabel ids a thread must all carry on top of
folder, matched exactly.openemail.WithSortstringnewest(the default),oldest,senderorsubject, the four orders of the thread list in the app.senderandsubjectare alphabetical, newest first within one sender or subject.openemail.WithDateFromtime.TimeKeeps threads whose newest message arrived at or after this instant. A
time.Time.openemail.WithDateTotime.TimeKeeps threads whose newest message arrived at or before this instant. Both ends are included, and
dateFromafterdateTois a 422.openemail.WithFromContactsboolWhen true, keeps only threads whose newest message came from a saved contact. A key limited to some addresses reads the contacts its owner saved.
openemail.WithSemanticboolWhen true, the plain words of
querymatch by meaning instead of spelling, in any language, and the closest threads come first along with every thread the words match as text. Operators and the other filters still apply andsortdoes not. Ignored when the workspace has search by meaning turned off.openemail.WithCategorystringKeeps only the threads sorted into this inbox tab:
primary,promotions,updates,socialorforums.primaryis every thread in no other tab.openemail.WithAddressstringKeeps only the threads delivered to this address, the address filter of the thread list. One the key does not reach returns nothing rather than failing.
openemail.WithLimitintPage size for each request, a whole number from 1 to 100. Defaults to 25.
openemail.WithCursorstringA
NextCursorto start from instead of the first page.openemail.WithAPIKeystringOverrides the client's API key for every page of this walk.
Rückgabe
An *openemail.Iterator yielding a map with object set to thread and id per step.
Beispiel
for thread, err := range client.Threads.Iterate(ctx, openemail.WithFolder("inbox"), openemail.WithQuery("receipt newer_than:30d"), openemail.WithLimit(100)).All() { if err != nil { return err } fmt.Println(thread.String("id"))}Hinweise
The iterator is lazy, so an abandoned loop costs only the pages it consumed.
A cancelled context ends the loop with an
*openemail.Errorrather than ending it quietly.
Auch verfügbar über
- API
GET /threads- TypeScript
threads.iterate()- Python
threads.iterate()- Ruby
threads.iterate- PHP
threads->iterate- Java
threads().iterate- C#
Threads.IterateAsync
Threads.Get
Read a thread with every message on it
Get(ctx context.Context, id string, opts ...openemail.RequestOption) (openemail.Object, error)Returns the whole conversation, oldest message first, with the labels the thread sits in and its unread state. Unsent draft replies are included in messages with isDraft: true, which is why messageCount, the length of messages, can be higher than totalReplies, which counts only real messages.
Messages are passed through as the mailbox stored them, so a message object is an open record rather than a fixed field list. The one field the API commits to is encryption. When encryption.format is pgp-mime, pgp-inline or smime-encrypted, the message is sealed and its body is empty or holds armour. pgp-signed and smime-signed are ordinary readable mail. A message with no encryption at all was stored before detection existed, so its absence says nothing about whether it was plaintext.
Each message's tags and unread are overwritten on read with the thread's current labels and unread flag, so they describe the thread and not that one message.
Parameter
idstringErforderlichThread id, as returned by
Listor carried on a message.openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with id echoed from the request, messages, labels as a map with id, name and color, messageCount, hasUnread, totalReplies and deliveredTo, the workspace address the thread belongs to (null when none was recorded).
Beispiel
thread, err := client.Threads.Get(ctx, "CAHk7pQ2x9LmZ4-mail.example.com")if err != nil { return err} fmt.Println(thread.String("id"), thread.String("object"))Hinweise
A thread delivered to no address the key covers is a 404, exactly like one that does not exist.
hasUnreadmirrors theUNREADlabel, andUpdatewithreadis how you change it.Draft ids from
Drafts.Listopen here too, because a draft is stored as a thread labelledDRAFT.
Auch verfügbar über
- API
GET /threads/{id}- TypeScript
threads.get()- Python
threads.get()- Ruby
threads.get- PHP
threads->get- Java
threads().get- C#
Threads.GetAsync- CLI
openemail threads get
Threads.Update
Mark a thread read or unread and change its labels
Update(ctx context.Context, id string, patch openemail.Body, opts ...openemail.RequestOption) (openemail.Object, error)Adds and removes labels on a thread in one call. read is shorthand for the UNREAD label: true removes it and false adds it. At least one of read, a non empty addLabelIds or a non empty removeLabelIds is required, each list takes at most 50 ids, and any other key is a 422 because the body is strict.
Folders are labels too, so archiving is addLabelIds: ['ARCHIVE'] with removeLabelIds: ['INBOX'], the same pair the app uses. TRASH, SNOOZED and DRAFT are refused in either list with 422 label_not_directly_settable, because each needs a step this route cannot take. Use Trash and Snooze for those.
User label ids come from Labels.List, and the system ids such as ARCHIVE, STARRED and UNREAD are taken in any case. An id in addLabelIds that names no label is refused with 422 label_not_found and nothing on the thread changes, so create the label with Labels.Create first. An unknown id in removeLabelIds is not an error, since the thread cannot carry it. Removals are applied before additions, so an id in both lists ends up on the thread.
Parameter
idstringErforderlichThread id.
readbooltrueremovesUNREAD,falseadds it.addLabelIds[]stringLabel ids to put on the thread, at most 50, each naming a label, never
TRASH,SNOOZEDorDRAFT.removeLabelIds[]stringLabel ids to take off the thread, at most 50, never
TRASH,SNOOZEDorDRAFT.openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with id, addedLabelIds and removedLabelIds. Both lists echo the request, with system ids upper cased, plus the UNREAD change that read implies, not what actually changed.
Beispiel
updated, err := client.Threads.Update(ctx, "CAHk7pQ2x9LmZ4-mail.example.com", openemail.Body{ "read": true, "addLabelIds": []string{"ARCHIVE", "USER_RECEIPTS"}, "removeLabelIds": []string{"INBOX"},})if err != nil { return err} fmt.Println(updated.String("id"), updated.String("object"))Hinweise
The SDK retries this call after a network failure or a retryable status, which is safe because adding a label already present or removing one already gone changes nothing.
The thread is looked up before the body is validated, so a wrong id is a 404 even when the patch is also invalid.
User label ids look like
USER_RECEIPTS. Take them fromLabels.Listrather than building them.
Auch verfügbar über
- API
PATCH /threads/{id}- TypeScript
threads.update()- Python
threads.update()- Ruby
threads.update- PHP
threads->update- Java
threads().update- C#
Threads.UpdateAsync- CLI
openemail threads update
Threads.Trash
Move a thread to the Bin
Trash(ctx context.Context, id string, opts ...openemail.RequestOption) (openemail.Object, error)Adds TRASH and removes INBOX, SPAM, SNOOZED and ARCHIVE in one step, which is what the app's delete does. Doing half of that through Update would leave the thread listed in both the Bin and its old folder, which is why Update refuses TRASH.
Nothing is deleted. The thread stays readable with Get and lists under folder: 'trash'. Calling this on a thread that is already in the Bin changes nothing and returns the same body, which is why the SDK retries it.
Parameter
idstringErforderlichThread id.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with object set to thread, id and trashed set to true.
Beispiel
result, err := client.Threads.Trash(ctx, "CAHk7pQ2x9LmZ4-mail.example.com")if err != nil { return err} fmt.Println(result.String("id"), result.Bool("trashed"))Hinweise
Restoretakes a thread back out of the Bin.UpdaterefusesTRASHinremoveLabelIdsas well as inaddLabelIds.Trashing a snoozed thread also cancels its scheduled wake, so it does not reappear in the inbox later.
A thread delivered to no address the key covers is a 404.
Auch verfügbar über
- API
POST /threads/{id}/trash- TypeScript
threads.trash()- Python
threads.trash()- Ruby
threads.trash- PHP
threads->trash- Java
threads().trash- C#
Threads.TrashAsync- CLI
openemail threads trash
Threads.Snooze
Hide a thread until a set time
Snooze(ctx context.Context, id string, wakeAt time.Time, opts ...openemail.RequestOption) (openemail.Object, error)Adds SNOOZED, removes INBOX and stores a wake time, all in one call. Both halves matter: the label hides the thread and the stored wake time is what brings it back. A thread labelled SNOOZED any other way would never return, which is why Update refuses that label.
wakeAt takes a time.Time or an ISO 8601 string. A time.Time is sent as an ISO 8601 instant, and the server answers 422 invalid_parameter on wakeAt when the value does not parse or is not in the future. Snoozing a thread that is already snoozed replaces its wake time.
Threads are woken by an hourly sweep, so one comes back at the first sweep after wakeAt, up to about an hour late. Opening the Snoozed folder in the app wakes overdue threads straight away. A thread always wakes into the inbox.
Parameter
idstringErforderlichThread id.
wakeAttime.TimeErforderlichWhen the thread should return, a future instant.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with id and snoozedUntil, the wake time normalised to a UTC ISO string.
Beispiel
snoozed, err := client.Threads.Snooze(ctx, "CAHk7pQ2x9LmZ4-mail.example.com", time.Now().Add(24*time.Hour))if err != nil { return err} fmt.Println(snoozed.String("snoozedUntil"))Hinweise
Only
INBOXis removed, so a thread snoozed from another folder keeps that folder's label while it sleeps and wakes carrying both.A string with no zone offset is read in the server's local zone, so send
Zor an explicit offset.The SDK retries this call, which is safe because a repeat stores the same wake time.
Auch verfügbar über
Threads.Unsnooze
Bring a snoozed thread back now
Unsnooze(ctx context.Context, id string, opts ...openemail.RequestOption) (openemail.Object, error)Adds INBOX, removes SNOOZED and deletes the stored wake time, so the thread returns immediately and the hourly sweep leaves it alone afterwards.
A thread that is not snoozed is left where it is, so an archived thread stays archived, and the response still reports snoozedUntil: null.
Parameter
idstringErforderlichThread id.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with id and snoozedUntil set to null.
Beispiel
result, err := client.Threads.Unsnooze(ctx, "CAHk7pQ2x9LmZ4-mail.example.com")if err != nil { return err} fmt.Println(result.String("snoozedUntil"))Hinweise
Removing
SNOOZEDthroughUpdateis refused with 422label_not_directly_settable, because it would leave the wake time scheduled.Safe to retry, and the SDK does: a second call applies the same labels and deletes a wake time that is already gone.
Auch verfügbar über
Threads.Mute
Mute a thread
Mute(ctx context.Context, id string, opts ...openemail.RequestOption) (openemail.Object, error)Mutes a conversation, as Mute does in the app. A thread in the inbox moves to the archive, and from then on new mail in it goes straight to the archive, unread, with no push, sound or desktop notice. A webhook for that mail carries muted: true.
Thread state belongs to the whole workspace, so the thread is muted for everyone on it, and mail addressed only to you does not bring it back. Calling it again changes nothing, which is why the SDK retries it. Update with MUTE in addLabelIds does the same.
Parameter
idstringErforderlichThread id.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with object set to thread, id and muted set to true.
Beispiel
muted, err := client.Threads.Mute(ctx, "CAHk7pQ2x9LmZ4-mail.example.com")if err != nil { return err} fmt.Println(muted.String("id"), muted.Bool("muted"))Hinweise
Only a thread in the inbox moves. One in Sent, the archive or Snoozed stays where it is.
A muted thread carries the built-in
MUTElabel, whichGetshows among its labels andis:mutedfinds inquery.Unmutetakes the mute off. A thread delivered to no address the key covers is a 404.
Auch verfügbar über
- API
POST /threads/{id}/mute- TypeScript
threads.mute()- Python
threads.mute()- Ruby
threads.mute- PHP
threads->mute- Java
threads().mute- C#
Threads.MuteAsync- CLI
openemail threads mute
Threads.Unmute
Take the mute off a thread
Unmute(ctx context.Context, id string, opts ...openemail.RequestOption) (openemail.Object, error)Takes the mute off, so the next message in the thread arrives in the inbox and alerts people again.
The thread stays where it is. Move it back with Update and INBOX in addLabelIds if you want it in the inbox now. A thread that is not muted is left as it is, which is why the SDK retries this call.
Parameter
idstringErforderlichThread id.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with object set to thread, id and muted set to false.
Beispiel
result, err := client.Threads.Unmute(ctx, "CAHk7pQ2x9LmZ4-mail.example.com")if err != nil { return err} fmt.Println(result.Bool("muted"))Hinweise
Unmuting is for the whole workspace, as muting is: the thread alerts everyone on it again.
A thread delivered to no address the key covers is a 404.
Auch verfügbar über
Threads.ListAttachments
List a message's attachments with their content
ListAttachments(ctx context.Context, id string, messageID string, opts ...openemail.RequestOption) ([]openemail.Object, error)Returns the attachments of one message with each file's bytes inlined as base64 in content. The thread is checked first and then the message, so a messageId that is not on that thread is a 404 even when it exists elsewhere in the mailbox. Take message ids from the messages of Threads.Get.
This is the display list. The ciphertext of an encrypted envelope is in it and downloads like any other file, named encrypted-message.asc when it arrived without a name. The PGP/MIME version part and any detached signature are held out on purpose. Every part keeps its id in the message's encryption.parts, and for those two the id is a correlation key only: no route returns their bytes.
Every file comes back whole in a single response, with no size cap and no range reads, so a message carrying large files makes a large response.
Parameter
idstringErforderlichThread id the message belongs to.
messageIDstringErforderlichMessage id from that thread's
messages.openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
A []openemail.Object, each with attachmentId, filename, contentType, size and base64 content.
Beispiel
files, err := client.Threads.ListAttachments(ctx, "CAHk7pQ2x9LmZ4-mail.example.com", "thr_9e3b7c1a5f2d8e40b6a9c3f1")if err != nil { return err} for _, attachment := range files { fmt.Println(attachment.String("content"), attachment.String("filename"), attachment.String("contentType"))}Hinweise
When the stored bytes for a file cannot be found,
contentis an empty string rather than null, so check its length before decoding.Both ids must match: a real message id paired with the wrong thread id is a 404
resource_not_found.A thread delivered to no address the key covers is a 404 before the message is looked at.
Auch verfügbar über
Threads.ListNotes
List the notes on a thread
ListNotes(ctx context.Context, id string, opts ...openemail.RequestOption) ([]openemail.Object, error)Returns every note on one thread, the Notes panel of the reading pane: pinned notes first, then the rest in the order they were arranged.
Notes are private to a person. A key reads and writes the notes of the workspace owner, and an app those of the person who connected it. A key limited to particular addresses reaches only the notes on threads that arrived at them.
Parameter
idstringErforderlichThread id.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
A []openemail.Object, each with id, threadId, content, color, pinned, order, createdAt and updatedAt.
Beispiel
notes, err := client.Threads.ListNotes(ctx, "CAHk7pQ2x9LmZ4-mail.example.com")if err != nil { return err} for _, note := range notes { fmt.Println(note.Bool("pinned"), note.String("content"))}Hinweise
A thread delivered to no address the key covers is a 404.
Auch verfügbar über
Threads.CreateNote
Add a note to a thread
CreateNote(ctx context.Context, id string, body openemail.Body, opts ...openemail.RequestOption) (openemail.Object, error)Pins a private note to a thread, as the Notes panel does. A new note goes after the others, and pinned keeps it at the top.
Notes are private to a person. A key reads and writes the notes of the workspace owner, and an app those of the person who connected it. A key limited to particular addresses reaches only the notes on threads that arrived at them.
Parameter
idstringErforderlichThread id.
contentstringErforderlichThe text of the note, up to 20,000 characters. Leading and trailing spaces are trimmed.
colorstringOne of the eight the app offers:
default,red,orange,yellow,green,blue,purpleorpink. Defaults todefault.pinnedboolKeeps the note above the others. Defaults to false.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object for the new note.
Beispiel
note, err := client.Threads.CreateNote(ctx, "CAHk7pQ2x9LmZ4-mail.example.com", openemail.Body{ "content": "Waiting on the signed contract before replying.", "color": "yellow", "pinned": true,})if err != nil { return err} fmt.Println(note.String("id"))Hinweise
The SDK does not retry it, because a second call would add a second note.
Auch verfügbar über
Threads.UpdateNote
Change a note
UpdateNote(ctx context.Context, id string, noteID string, patch openemail.Body, opts ...openemail.RequestOption) (openemail.Object, error)Changes the text of a note, its colour or whether it is pinned. Give at least one of the three. A note id that is not on this thread is a 404, even when the note exists on another thread.
Parameter
idstringErforderlichThread id.
noteIDstringErforderlichThe note's id, from
ListNotes.contentstringThe new text, up to 20,000 characters.
colorstringThe new colour.
pinnedboolPins or unpins it.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object as it is now.
Beispiel
note, err := client.Threads.UpdateNote( ctx, "CAHk7pQ2x9LmZ4-mail.example.com", "b3d1f0c2-7a4e-4f7b-9c1d-2e8f6a5b4c3d", openemail.Body{"pinned": false},)if err != nil { return err} fmt.Println(note.Bool("pinned"))Hinweise
Safe to repeat: setting the same values twice leaves the note as it was.
Auch verfügbar über
Threads.DeleteNote
Delete a note
DeleteNote(ctx context.Context, id string, noteID string, opts ...openemail.RequestOption) (openemail.Object, error)Deletes a note for good. There is no bin for notes.
Parameter
idstringErforderlichThread id.
noteIDstringErforderlichThe note's id, from
ListNotes.openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with object set to note, id, threadId and deleted set to true.
Beispiel
note, err := client.Threads.DeleteNote(ctx, "CAHk7pQ2x9LmZ4-mail.example.com", "b3d1f0c2-7a4e-4f7b-9c1d-2e8f6a5b4c3d")if err != nil { return err} fmt.Println(note.String("id"), note.String("object"))Hinweise
The SDK does not retry a delete. A 404 on your own second attempt after a lost response means the first one worked.
Auch verfügbar über
Threads.ReorderNotes
Arrange the notes on a thread
ReorderNotes(ctx context.Context, id string, ids []string, opts ...openemail.RequestOption) ([]openemail.Object, error)Sets the order of every note on a thread at once, first to last, as dragging them in the Notes panel does. Pinned notes still come first.
ids has to name every note on the thread exactly once. Anything else is a 422 invalid_parameter on ids, and nothing moves.
Parameter
idstringErforderlichThread id.
ids[]stringErforderlichEvery note id on the thread, in the order you want them.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
A []openemail.Object in the new order.
Beispiel
notes, err := client.Threads.ReorderNotes(ctx, "CAHk7pQ2x9LmZ4-mail.example.com", []string{ "b3d1f0c2-7a4e-4f7b-9c1d-2e8f6a5b4c3d", "0f9e8d7c-6b5a-4c3d-8e2f-1a0b9c8d7e6f",})if err != nil { return err} for _, note := range notes { fmt.Println(note.String("id"), note.Bool("pinned"))}Hinweise
Safe to repeat: the same order twice leaves the notes as they were.
Auch verfügbar über
Threads.Counts
Count the mail in each folder
Counts(ctx context.Context, opts ...openemail.RequestOption) (openemail.Object, error)Returns what the sidebar of the app shows: how many conversations each folder holds and how many of them are unread, how many drafts are waiting, how many conversations each of your labels has in each folder, how many inbox conversations sit in each inbox tab, and how many inbox conversations arrived at each address of the workspace.
folders has one row per folder, named by its label id in lower case: inbox, sent, spam, archive, Trash and snoozed, then draft, whose count is the drafts waiting to be sent and whose unread is always 0, then unread, whose count is the unread conversations in the inbox. labels has one row for each of your labels and each folder it has conversations in, a map with id, folder, count and unread, so a label with nothing in a folder has no row for it. categories has one row for each inbox tab, a map with category, count and unread, counting inbox conversations only: primary, promotions, updates, social and forums, where primary is everything not sorted into another tab. addresses counts the inbox per address the mail was delivered to, with null for mail that recorded none.
A key limited to particular addresses counts only the mail that arrived at them and the drafts written from them. address narrows every count to one address, and one the key does not reach counts nothing rather than failing.
Parameter
openemail.WithAddressstringCount only the mail delivered to this address.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with object set to mailbox_counts, folders, addresses, labels and categories, each folder a map with label, count and unread, each address a map with address and count, each label a map with id, folder, count and unread and each category a map with category, count and unread.
Beispiel
counts, err := client.Threads.Counts(ctx)if err != nil { return err} fmt.Println(counts.String("object"))Hinweise
Read only, so the SDK retries it after a network failure like any other read.
Auch verfügbar über
- API
GET /threads/counts- TypeScript
threads.counts()- Python
threads.counts()- Ruby
threads.counts- PHP
threads->counts- Java
threads().counts- C#
Threads.CountsAsync- CLI
openemail threads counts
Threads.Summary
Read the summary of a thread
Summary(ctx context.Context, id string, opts ...openemail.RequestOption) (openemail.Object, error)Returns the short AI summary the reading pane shows above a thread. A summary is written the first time it is asked for and then kept, and the first request after a newer message arrives writes it again, so reading one is cheap.
state is ready with the text in summary, pending while the first one is being written, or none when there is nothing to summarise, such as a thread holding a message that arrived encrypted, whose body OpenEmail never reads. While a newer summary is being written, the one before it comes back as ready. A pending answer starts the writing, so ask again a few seconds later.
Parameter
idstringErforderlichThread id.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with object set to thread_summary, threadId, state and summary, with summary null unless state is ready.
Beispiel
result, err := client.Threads.Summary(ctx, "CAHk7pQ2x9LmZ4-mail.example.com")if err != nil { return err} fmt.Println(result.String("state"), result.String("summary"))Hinweise
Summaries spend no AI actions, whether one is written or only read.
A thread delivered to no address the key covers is a 404.
Auch verfügbar über
Threads.ReplySuggestions
Suggest replies to a thread
ReplySuggestions(ctx context.Context, id string, opts ...openemail.RequestOption) (openemail.Object, error)Returns up to three short replies to the latest message of the thread, the ones the reading pane offers under it. Each has a label, a few words that say what it answers, and a body, the reply itself in plain text, ready to send with Emails.Send or to keep with Drafts.Create. They are written in the language of that message and the voice of the mail this workspace sends, from the conversation, what was written to this correspondent before, what is known about their organisation and, when the message asks for a time, the busy times of the calendar.
Suggestions are written once for each new message and kept, so asking again is free until another message arrives. state is ready with the suggestions, pending while they are being written, so ask again a few seconds later, or none when the message needs no reply: your own reply came last, or it is a newsletter, an automated notice, mail from a no-reply address, spam or an encrypted message. Every thread is none in a workspace that turned ReplySuggestions off with Settings.Update.
sources names the knowledge base items the suggestions drew on: the pinned notes at the levels of the receiving address and the items whose passages matched the message, each a KnowledgeSourceRef with id, title, kind, scope and url. It is empty when none were used.
Parameter
idstringErforderlichThread id.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with object set to reply_suggestions, threadId, messageId, state, suggestions and sources, with messageId naming the message they answer, suggestions empty unless state is ready and sources the knowledge base items they drew on.
Beispiel
result, err := client.Threads.ReplySuggestions(ctx, "CAHk7pQ2x9LmZ4-mail.example.com")if err != nil { return err} fmt.Println(result.String("state"))Hinweise
Writing suggestions spends none of the workspace's AI actions. A workspace has suggestions written for a limited number of new messages a day, and past it a thread reads
noneuntil the next day.A thread delivered to no address the key covers is a 404.
A server without AI answers 409
ai_not_configured.
Auch verfügbar über
Threads.Restore
Take a thread out of the Bin
Restore(ctx context.Context, id string, opts ...openemail.RequestOption) (openemail.Object, error)Puts a thread back in the inbox, out of the Bin and out of Spam, which is what Restore from Bin and Move to inbox do in the app. It is the undo of Trash.
Calling it on a thread that is already in the inbox changes nothing and returns the same body, which is why the SDK retries it.
Parameter
idstringErforderlichThread id.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with object set to thread, id and restored set to true.
Beispiel
restored, err := client.Threads.Restore(ctx, "CAHk7pQ2x9LmZ4-mail.example.com")if err != nil { return err} fmt.Println(restored.Bool("restored"))Hinweise
A thread that was archived before it went to the Bin comes back to the inbox, not to the archive.
A thread delivered to no address the key covers is a 404.
Auch verfügbar über
Threads.Delete
Delete a thread for good
Delete(ctx context.Context, id string, opts ...openemail.RequestOption) (openemail.Object, error)Deletes every message in a thread, with its attachments, which is what Delete from Bin does in the app. It cannot be undone.
It works on a thread in any folder, so call Trash instead when you only mean to throw the thread away: a trashed thread stays readable and Restore brings it back.
Parameter
idstringErforderlichThread id.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with object set to thread, id and deleted set to true.
Beispiel
thread, err := client.Threads.Delete(ctx, "CAHk7pQ2x9LmZ4-mail.example.com")if err != nil { return err} fmt.Println(thread.String("id"), thread.String("object"))Hinweise
The SDK does not retry a delete. A 404 on your own second attempt after a lost response means the first one worked.
A 500
thread_delete_failedmeans nothing was removed, so the call is safe to repeat.A thread delivered to no address the key covers is a 404.
Auch verfügbar über
- API
DELETE /threads/{id}- TypeScript
threads.delete()- Python
threads.delete()- Ruby
threads.delete- PHP
threads->delete- Java
threads().delete- C#
Threads.DeleteAsync- CLI
openemail threads delete
Threads.Unsubscribe
Unsubscribe from the sender of a thread
Unsubscribe(ctx context.Context, id string, opts ...openemail.RequestOption) (openemail.Object, error)Does what the Unsubscribe button of the reading pane does: finds the subscription behind the newest message of the thread that carries a List-Unsubscribe header and unsubscribes from it the way the sender asks for, with a one-click request or an unsubscribe email. A sender that only offers a page cannot be unsubscribed by a program, so method is link and url is the page a person has to open.
A thread with no unsubscribe header is a 422 unsubscribe_unsupported, and a thread delivered to no address the key covers is a 404.
Parameter
idstringErforderlichThread id.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with object set to unsubscribe, threadId, subscriptionId, method, url and binned.
Beispiel
result, err := client.Threads.Unsubscribe(ctx, "CAHk7pQ2x9LmZ4-mail.example.com")if err != nil { return err} fmt.Println(result.String("method"))Hinweise
The SDK does not retry it, because a second call can send a second unsubscribe email.
Auch verfügbar über
Threads.GetEvent
Read the event a thread carries
GetEvent(ctx context.Context, id string, opts ...openemail.RequestOption) (openemail.Object, error)Returns the calendar event that came with an invitation in the thread, as the invitation card of the reading pane shows it. Answer it with Calendar.RespondToEvent.
Parameter
idstringErforderlichThread id, as
Threads.Listreturns it.openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object, as Calendar.GetEvent returns it.
Beispiel
event, err := client.Threads.GetEvent(ctx, "thr_6d1a9c4e2b7f30d85e1c4a92")if err != nil { return err} fmt.Println(event.String("summary"), event.String("start"))Hinweise
A thread with no event, or one the key does not reach, is a 404.
Auch verfügbar über
Threads.ListSenderCategories
List the senders that always go to one inbox tab
ListSenderCategories(ctx context.Context, opts ...openemail.RequestOption) ([]openemail.Object, error)Returns the senders whose mail always goes to one inbox tab, by address. New mail is sorted into Primary, Promotions, Updates, Social or Forums by plain rules, and a choice saved here wins over them. List takes category to read one tab.
The choices belong to the workspace and apply to every address in it. A workspace holds at most 2,000 of them, and they come back as one plain array with no paging.
Parameter
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
A []openemail.Object, each a map with object set to sender_category, sender, category and updatedAt, with sender in lower case and category the tab their mail goes to.
Beispiel
choices, err := client.Threads.ListSenderCategories(ctx)if err != nil { return err} for _, category := range choices { fmt.Println(category.String("sender"), category.String("category"))}Hinweise
A key or an app limited to particular addresses or domains can read the choices but not change them.
Read only, so the SDK retries it after a network failure like any other read.
Auch verfügbar über
Threads.SetSenderCategory
Always sort a sender into one inbox tab
SetSenderCategory(ctx context.Context, email string, category string, opts ...openemail.RequestOption) (openemail.Object, error)Saves the tab for one sender and moves the inbox threads whose newest message is from them, up to the newest 1,000, into it. Mail from them is sorted there from now on, whatever the rules would say. Saving again replaces the choice.
A workspace holds at most 2,000 choices, and the call past that is a 422 sender_category_limit_reached. They apply to every address in the workspace, so a key or an app limited to particular addresses or domains can read them but not change them, and gets a 422 capability_unsupported.
Parameter
emailstringErforderlichThe address of the sender, compared without case.
categorystringErforderlichThe inbox tab their mail goes to:
primary,promotions,updates,socialorforums.openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with object set to sender_category, sender, category and updatedAt, with sender in lower case.
Beispiel
choice, err := client.Threads.SetSenderCategory(ctx, "[email protected]", "promotions")if err != nil { return err} fmt.Println(choice.String("sender"), choice.String("category"), choice.String("updatedAt"))Hinweise
An address or a category that is not valid is a 422
invalid_parameter.Choosing
primarykeeps a sender out of the other tabs, which is how to stop a newsletter you read from being sorted away.The SDK retries this call after a network failure, which is safe because saving the same choice twice leaves the same choice.
Auch verfügbar über
Threads.ClearSenderCategory
Remove the tab chosen for a sender
ClearSenderCategory(ctx context.Context, email string, opts ...openemail.RequestOption) (openemail.Object, error)Removes the choice, so new mail from the sender is sorted by the rules again. Threads already sorted stay where they are.
Parameter
emailstringErforderlichThe address of the sender, compared without case.
openemail.WithAPIKeystringOverrides the client's API key for this call only.
Rückgabe
An openemail.Object with object set to sender_category, sender and deleted set to true, with sender in lower case.
Beispiel
removed, err := client.Threads.ClearSenderCategory(ctx, "[email protected]")if err != nil { return err} fmt.Println(removed.String("sender"), removed.Bool("deleted"))Hinweise
A sender with no saved choice is a 404. The SDK does not retry a delete, so a 404 on your own second attempt after a lost response means the first one worked.
A key or an app limited to particular addresses or domains cannot change the choices, and gets a 422
capability_unsupported.