Threads
`threads.list`, `list_all`, `iterate`, `get`, `update`, `trash`, `snooze`, `unsnooze` und `list_attachments`.
Lesen
page = client.threads.list( folder: "inbox", query: "from:ada", label_ids: ["INBOX", "IMPORTANT"], limit: 25) if page.next_cursor next_page = client.threads.list(folder: "inbox", cursor: page.next_cursor) puts next_page.items.sizeend thread = client.threads.get("CAHk7pQ2x9LmZ4-mail.example.com")puts thread[:messageCount], thread[:hasUnread], thread[:totalReplies]Die API paginiert Threads mit einem pageToken. Der Client reicht ihn als next_cursor heraus und nimmt ihn als cursor: wieder entgegen, wie bei jeder anderen Liste, und list_all sowie iterate folgen ihm für Sie. Er ist opak: Geben Sie genau den erhaltenen Wert zurück und bauen Sie nie selbst einen.
Die Listenfilter sind Ruby-Keywords in snake_case (label_ids:, date_from:), während die Felder eines Request-Bodys die camelCase-Namen der API behalten (addLabelIds: bei update). Ein Thread kommt als Hash mit Symbol-Schlüsseln zurück, thread[:messageCount] liest also die Anzahl.
last_week = client.threads.list_all( sort: "oldest", date_from: Time.now - (7 * 86_400), date_to: Time.now, from_contacts: true)puts last_week.size client.threads.iterate(sort: "sender") do |thread| puts thread[:id]endsort:, date_from:, date_to: und from_contacts: sind die eigenen Steuerelemente der Threadliste. sort: ist newest, oldest, sender oder subject, und OpenEmail::THREAD_SORTS nennt sie. Die Datumswerte nehmen ein Time, ein DateTime oder einen ISO-8601-String mit Uhrzeit und Offset, und beide Enden sind eingeschlossen. Ein Ruby-Date wird als bloßes Datum gesendet, das diese Felder mit einem 422 ablehnen. from_contacts: true behält Mail, deren neueste Nachricht von einem gespeicherten Kontakt kam. Jede Sortierung lässt sich bis zum Ende blättern, ohne einen Thread zu überspringen oder zu wiederholen.
list_all gibt ein einziges Array zurück, sobald die letzte Seite da ist. iterate übergibt jeden Thread an einen Block und holt die nächste Seite erst, wenn die Schleife sie braucht. Ohne Block gibt es einen Enumerator zurück, first(10) oder lazy stoppen also, sobald sie haben, was sie brauchen.
Organisieren
thread_id = "CAHk7pQ2x9LmZ4-mail.example.com" client.threads.update(thread_id, read: true, addLabelIds: ["USER_DONE"], removeLabelIds: ["INBOX"]) client.threads.trash(thread_id)client.threads.snooze(thread_id, Time.now + 86_400)client.threads.unsnooze(thread_id)Der Gelesen-Status ist hier auf jedem Backend ein Label und reist daher mit den Label-Listen mit, und die Reihenfolge steht fest, wenn Sie beides setzen: Entfernungen werden vor Hinzufügungen angewendet, eine id in beiden Listen landet also am Thread. Mindestens eines der drei Felder muss vorhanden sein.
addLabelIds nimmt ids aus labels.list und die System-ids wie ARCHIVE und STARRED. Eine id, die kein Label benennt, wird mit einem 422 label_not_found abgelehnt statt angelegt. Legen Sie das Label also zuerst mit labels.create an. client.threads.list(folder: "USER_DONE") listet jeden Thread mit einem Label, egal in welchem Ordner.
Anhänge an einer Nachricht
files = client.threads.list_attachments("CAHk7pQ2x9LmZ4-mail.example.com", "message_4c1b257a") files.each do |file| puts "#{file[:filename]} #{file[:contentType]} #{file[:size]}" File.binwrite(file[:filename], file[:content].unpack1("m")) unless file[:content].to_s.empty?endlist_attachments gibt ein Array von Hashes zurück. content ist base64, das unpack1("m") in einen binären String verwandelt, und ein leerer String, wenn die gespeicherten Bytes nicht gefunden werden konnten. Prüfen Sie daher vor dem Dekodieren die Länge. Der Ciphertext einer verschlüsselten Nachricht steht in dieser Liste und wird wie jede andere Datei heruntergeladen. Der Versions-Part von PGP/MIME und eine etwaige abgetrennte Signatur dagegen nicht. Sie behalten ihre ids in encryption.parts und sonst nichts.
Eine verschlüsselt eingegangene Nachricht
Dieses Gem verschlüsselt und entschlüsselt nicht. Es kann keine Nachricht öffnen, die jemand anderes verschlüsselt hat, und keine verschlüsselte senden. Die Sendeanfrage wird abgelehnt, wenn sie einen Verschlüsselungsmarker mitführt, denn ein Client ohne Schlüssel hat keinen Grund, einen zu behaupten. Schlüssel, die in der OpenEmail-App erzeugt wurden, leben in dem Browser, der sie erzeugt hat, und erreichen hier nichts. Öffnet dieser Browser eine versiegelte Nachricht, bleibt der Klartext in ihm, und die gespeicherte Nachricht, die dieser Aufruf liest, ist weiterhin Ciphertext. Was threads.get Ihnen liefert, ist der Umschlag, als solcher erkannt. Eine Nachricht, die PGP- oder S/MIME-verpackt eingegangen ist, trägt einen encryption-Hash, ein leerer decodedBody ist damit nicht mehr das Einzige, was Sie in die Hand bekommen. encryption ist das einzige Feld einer Nachricht, auf das sich die API festlegt, denn es ist das eine, bei dessen Fehlen Sie sich kein Raten leisten können.
thread = client.threads.get("CAHk7pQ2x9LmZ4-mail.example.com") thread[:messages].each do |message| next unless message[:encryption] next unless OpenEmail.sealed?(message) warn "cannot read this one: #{message[:encryption][:format]}"endVerzweigen Sie über OpenEmail.sealed?, nie über das Vorhandensein des Feldes. Zwei der fünf Formate, pgp-signed und smime-signed, beschreiben einen Body, der im Klartext neben einer abgetrennten Signatur eingegangen ist. Eine Prüfung auf bloßes Vorhandensein verbirgt also Mail, die niemand verbergen musste, und die Person kann sie weder sehen noch erklären. Genau dafür gibt es OpenEmail.sealed?. Der Server nennt die versiegelte Menge einmal, die Kopie des Gems wird aus derselben Quelle erzeugt, und eine dritte, von Hand abgeschriebene Kopie ist die, die auseinanderdriftet. OpenEmail::MESSAGE_ENCRYPTION_FORMATS nennt alle fünf Formate.
Fehlen bedeutet nicht Klartext. encryption fehlt bei jeder Nachricht, die vor dem Ausliefern der Erkennung gespeichert wurde, und bei allem, was das Postfach über einen Weg erreicht hat, auf dem der Detektor nie lief. Es hält fest, dass niemand nachgesehen hat – eine Tatsache über unsere Abdeckung und nicht über die Mail –, und nichts trägt es nachträglich nach.
Worin sich diese vom Rest unterscheiden
- Jeder Eintrag in den
messageseines Threads ist der Hash, den das Postfach gespeichert hat, ohne feste Liste von Feldern. Mehr zu versprechen hieße, dass der Client eine Normalisierung behauptet, die niemand vornimmt.encryptionist das einzige Feld, auf das sich die API trotzdem festlegt, denn ein Client, der nicht darüber verzweigen kann, liest eine versiegelte Nachricht als leere. - Eine Anfrage, die nicht getreu bedient werden kann, ergibt einen 422
capability_unsupported, ausgelöst alsOpenEmail::ValidationError, und keine Antwort, die richtig aussieht und stillschweigend falsch ist.
Parameter: threads.list
folderString- Welcher Ordner aufgelistet wird. Der Server setzt standardmäßig `inbox`, ein Weglassen schränkt die Auflistung also ein, statt sie auf alles auszuweiten. Der Wert gilt auch für eine `query:`-Suche, sofern die Query nicht selbst einen Ordner mit `in:` oder ein Ordner-`is:` wie `is:sent` benennt.
queryString- Die Suchsyntax des Postfachs. Einfache Wörter müssen alle vorkommen und passen jeweils unscharf: Groß- und Kleinschreibung, Akzente und Trennzeichen werden ignoriert, und ein Teil eines längeren Wortes zählt mit, sodass `min` und `ben jamin` beide „Benjamin“ finden. Eine Phrase in Anführungszeichen wird bis auf Groß- und Kleinschreibung und Akzente wörtlich gesucht, `"ben jamin"` findet also „Ben-Jamin“ nicht, und Füllwörter werden verworfen, wenn sonst noch etwas zum Suchen bleibt. Wenn nichts genau passt, werden stattdessen ähnliche Schreibweisen geliefert, `benjimin` findet also „Benjamin“: Ein einfaches Wort oder der Wert von `from:`, `to:`, `cc:`, `subject:`, `body:`, `filename:` oder `label:` darf vom Anfang eines Wortes um einen Tippfehler (einen geänderten, fehlenden, zusätzlichen oder vertauschten Buchstaben) abweichen, wenn es vier bis sieben Buchstaben hat, und um zwei, wenn es acht oder mehr hat. Eine Phrase in Anführungszeichen, ein Wort mit einer Ziffer, ein kürzeres Wort und ein ausgeschlossenes Wort müssen weiterhin genau passen, und die folgenden Seiten suchen auf dieselbe Weise weiter. Grenzen Sie mit Operatoren wie `from:ada`, `label:Invoices`, `is:unread`, `has:pdf`, `before:2026/01/31` und `older_than:1y` ein und kombinieren Sie sie mit `OR`, Klammern und einem vorangestellten `-`. Ein Wert, den die Suche nicht verwenden kann, wird ignoriert und schränkt nicht ein. Wörter sowie die Operatoren `from:`, `to:`, `cc:`, `subject:` und `body:` lesen Absender, Empfänger und Betreff der neuesten Nachricht sowie die ersten 4.000 Zeichen ihres Bodys ohne Markup, während `filename:` und `has:` jeden Anhang der gesamten Konversation lesen und Labels und Ordner die gesamte Konversation. Eingegrenzt wird derselbe Index, den die ungefilterte Auflistung liest. Versiegelte Nachrichten speichern keinen Body-Text, daher können nur ihr Absender, ihre Empfänger und ihr Betreff treffen. Ein einfaches Wort trifft außerdem den Namen jedes Anhangs in der Konversation, ganz gleich, welche Nachricht ihn trug.
label_idsString or Array<String>- Schränkt die Auflistung auf Threads mit diesen Labels ein. Der Endpunkt nimmt einen kommagetrennten String entgegen, und der Client fügt ein Array oder ein Set für Sie zu einem solchen zusammen. Die Anzahl der genannten Labels ist unbegrenzt.
limitInteger- Wie viele Threads zurückgegeben werden, von 1 bis 100. Ohne Angabe verwendet der Handler 25. Der Standardwert liegt im Handler und nicht im Schema, daher verhalten sich ein fehlender Wert und eine ausdrückliche 25 gleich.
cursorString- Der `next_cursor` der vorherigen Seite, unverändert zurückgegeben. Es ist das `pageToken` der API unter dem Namen, den jede andere Liste verwendet, und es ist opak. Konstruieren oder bearbeiten Sie daher nie eines.
Antwort: OpenEmail::Page
itemsArray<Hash>- Ein Hash pro Thread auf dieser Seite, aus dem `data`-Umschlag der API herausgehoben. Jeder besteht nur aus einem `object`-Marker und einer `id`. Die Auflistung führt weder Betreff noch Snippet, Teilnehmer oder Labels mit. Für mehr rufen Sie `threads.get` für die gewünschten Threads auf.
items[].idString- Die id des Threads, gelesen als `item[:id]`, unverändert an `threads.get`, `threads.update` und die übrigen Aufrufe weiterzureichen. Es ist dieselbe id, ob die Zeile aus einer gefilterten Auflistung oder aus einer `query:`-Suche stammt.
has_more?Boolean- Ob es eine weitere Seite gibt, von der API übernommen, wo sie es angibt, und sonst aus `next_cursor` abgeleitet.
next_cursorString or nil- Das `nextPageToken` der API, als `cursor:` für die folgende Seite zurückzusenden, oder nil, wenn es keine weitere Seite gibt. Ein leeres Token wird zu nil normalisiert, sodass `if page.next_cursor` und eine nil-Prüfung übereinstimmen.