Belgelere geç
Python

Yazışmalar

`threads.list`, `list_all`, `iterate`, `get`, `update`, `trash`, `snooze`, `unsnooze` ve `list_attachments`.

Okuma

read_threads.py
from openemail import openemail page = openemail.threads.list(    folder='inbox',    query='from:ada',    label_ids=['INBOX', 'IMPORTANT'],    limit=25,) next_page = (    openemail.threads.list(folder='inbox', cursor=page['nextCursor'])    if page['nextCursor']    else None) thread = openemail.threads.get('thread_…')print(thread['messageCount'], thread['hasUnread'], thread['totalReplies'])

API, ileti dizilerini bir pageToken ile sayfalar. İstemci bunu size nextCursor olarak verir ve diğer tüm listelerde olduğu gibi cursor olarak geri alır; list_all ve iterate ise onu sizin yerinize takip eder. Değer opaktır: size verileni geri gönderin ve asla kendiniz bir tane oluşturmayın.

Liste filtreleri snake_case biçiminde anahtar sözcük argümanlarıdır (label_ids=, date_from=); bir istek gövdesinin anahtarları ise API'nin camelCase adlarını korur (update üzerinde addLabelIds). Bir sayfa ve bir konuşma sözlük olarak döner; bu yüzden onları page['nextCursor'] ve thread['messageCount'] ile okursunuz.

sort_threads.py
from datetime import datetime, timedelta, timezone from openemail import openemail now = datetime.now(timezone.utc) last_week = openemail.threads.list_all(    sort='oldest',    date_from=now - timedelta(days=7),    date_to=now,    from_contacts=True,) for thread in openemail.threads.iterate(sort='sender'):    print(thread['id'])

sort, date_from, date_to ve from_contacts konuşma listesinin kendi denetimleridir. sort newest, oldest, sender ya da subject olur, tarihler bir datetime ya da ISO 8601 dizesi alır ve iki uç da dahildir; from_contacts ise en yeni mesajı kayıtlı bir kişiden gelen postaları tutar. Her sıralama bir konuşmayı atlamadan ya da tekrarlamadan sonuna kadar sayfalanır. tzinfo içermeyen bir datetime yerel saat olarak okunur.

Düzenleme

organise_threads.py
from datetime import datetime, timedelta, timezone from openemail import openemail openemail.threads.update('thread_…', {    'read': True,    'addLabelIds': ['USER_DONE'],    'removeLabelIds': ['INBOX'],}) openemail.threads.trash('thread_…')openemail.threads.snooze('thread_…', datetime.now(timezone.utc) + timedelta(days=1))openemail.threads.unsnooze('thread_…')

Okundu durumu buradaki her arka uçta bir ETİKETTİR; bu yüzden etiket listeleriyle birlikte taşınır ve ikisini birden ayarladığınızda sıralama belirlenimlidir. Üç alandan en az biri bulunmalıdır.

addLabelIds, labels.list üzerinden gelen kimlikleri ve ARCHIVE ile STARRED gibi sistem kimliklerini alır. Hiçbir etiketi belirtmeyen bir kimlik oluşturulmak yerine 422 label_not_found ile reddedilir, bu yüzden etiketi önce labels.create ile oluşturun. threads.list(folder='USER_DONE'), hangi klasörde olursa olsun bir etiketi taşıyan her ileti dizisini listeler.

Bir iletideki ekler

attachments.py
import base64from pathlib import Path from openemail import openemail files = openemail.threads.list_attachments('thread_…', 'message_…') for file in files:    print(file['filename'], file['contentType'], file['size'])     if file['content']:        name = Path(file['filename']).name        Path(name).write_bytes(base64.b64decode(file['content']))

content base64'tür ve saklanan baytlar bulunamadığında boş bir string olur; bu yüzden çözmeden önce uzunluğunu denetleyin. Şifreli bir iletinin şifreli metni bu listede BULUNUR ve diğer dosyalar gibi indirilir; PGP/MIME sürüm parçası ile ayrık imzalar ise bulunmaz. Onların id'leri yalnızca encryption.parts içinde tutulur, başka hiçbir şey saklanmaz.

Şifreli olarak gelen bir ileti

Bu SDK ne şifreler ne de şifre çözer: başkasının şifrelediği bir mesajı açamaz ve şifreli bir mesaj gönderemez. Gönderme isteği bir şifreleme işareti taşıyorsa reddedilir; çünkü anahtarı olmayan bir istemcinin böyle bir iddiada bulunmaya hakkı yoktur. OpenEmail uygulamasında üretilen anahtarlar, onları üreten tarayıcıda yaşar ve buraya hiçbir şekilde ulaşmaz; o tarayıcı mühürlü bir mesajı açtığında düz metin tarayıcıda kalır ve bu çağrının okuduğu saklı mesaj hâlâ şifreli metindir. threads.get'in size verdiği şey, tanınmış hâliyle zarftır. PGP ya da S/MIME sarmalıyla gelen bir mesaj bir encryption sözlüğü taşır; böylece elinize tutuşturulan tek şey boş bir decodedBody olmaktan çıkar. Yokluğunu tahmine dayanarak atlatamayacağınız tek anahtar budur ve onu openemail.types içindeki MessageEncryption tanımlar.

encrypted_mail.py
import sys from openemail import is_sealed, openemail thread = openemail.threads.get('thread_…') for message in thread['messages']:    if not message.get('encryption'):        continue    if not is_sealed(message):        continue     print('cannot read this one:', message['encryption']['format'], file=sys.stderr)

Alanın varlığına göre değil, is_sealed ile dallanın. Beş biçimden ikisi, pgp-signed ve smime-signed, ayrık bir imzanın yanında AÇIK hâlde gelen bir gövdeyi tanımlar; bu yüzden varlığa göre kapı koymak, kimsenin gizlemesi gerekmeyen postayı gizler ve kullanıcı ne onu görebilir ne de açıklayabilir. is_sealed tam da bu nedenle gönderilir: sunucu mühürlü kümeyi bir kez bildirir ve birleşimden yazılmış üçüncü bir kopya, kayan kopyadır.

Yokluk, düz metin demek değildir. encryption, algılama yayımlanmadan önce saklanan her iletide ve algılayıcının hiç çalışmadığı bir yoldan posta kutusuna ulaşan her şeyde eksiktir. Kimsenin bakmadığını kaydeder; bu, postaya değil kapsamımıza dair bir olgudur ve hiçbir şey onu geriye dönük doldurmaz.

Bunların diğerlerinden ayrıldığı nokta

  • ThreadResource.messages içindeki her girdi bir MessageResource'tur: türü hiçbir alanı, encryption alanını bile adlandırmayan düz bir dict[str, Any]. Alanları türlemek, istemcinin kimsenin yapmadığı bir normalleştirmeyi iddia etmesi olurdu. encryption alanını message.get('encryption') ile okuyun ve is_sealed ile dallanın, çünkü buna göre dallanamayan bir istemci mühürlü bir mesajı boş bir mesaj olarak okur.
  • Sadakatle karşılanamayan bir istek, doğru görünüp sessizce yanlış olan bir yanıt değil, 422 capability_unsupported hatasıdır.

Parametreler: threads.list

folderstr
Hangi klasörün listeleneceği. Sunucu bunu varsayılan olarak `inbox` alır; bu yüzden atlamak, listelemeyi her şeye genişletmek yerine daraltır. Sorgu, `in:` ile ya da `is:sent` gibi bir klasör `is:` ifadesiyle kendisi bir klasör adlandırmadığı sürece, bu parametre bir `query` aramasına da uygulanır.
querystr
Posta kutusu arama sözdizimi. Düz sözcüklerin tümü geçmelidir ve her biri gevşek eşleşir: büyük/küçük harf, aksanlar ve ayırıcılar yok sayılır, daha uzun bir sözcüğün parçası da sayılır; bu yüzden hem `min` hem de `ben jamin` “Benjamin”i bulur. Tırnak içindeki bir ifade, büyük/küçük harf ve aksanlar dışında yazıldığı gibi eşleşir; bu yüzden `"ben jamin"` “Ben-Jamin”i bulmaz ve aranacak başka bir şey kaldığında dolgu sözcükleri düşürülür. Hiçbir şey tam olarak eşleşmediğinde onun yerine yakın yazımlar döndürülür; dolayısıyla `benjimin` “Benjamin”i bulur: düz bir sözcük ya da `from:`, `to:`, `cc:`, `subject:`, `body:`, `filename:` veya `label:` değeri, dört ile yedi harfliyse bir sözcüğün başından bir yazım hatasıyla (değişmiş, eksik, fazla ya da yer değiştirmiş bir harf), sekiz ya da daha fazla harfliyse iki hatayla ayrılabilir; tırnak içindeki bir ifade, rakam içeren bir sözcük, daha kısa bir sözcük ve dışlanan bir sözcük ise yine yalnızca tam eşleşir ve sonraki sayfalar da aynı biçimde arar. `from:ada`, `label:Invoices`, `is:unread`, `has:pdf`, `before:2026/01/31` ve `older_than:1y` gibi operatörlerle daraltın ve bunları `OR`, parantezler ve başa konan bir `-` ile birleştirin; aramanın kullanamadığı bir değer daraltma yapmak yerine yok sayılır. Sözcükler ile `from:`, `to:`, `cc:`, `subject:` ve `body:` operatörleri en son iletinin göndericisini, alıcılarını, konusunu ve gövdesinin işaretlemeden arındırılmış ilk 4.000 karakterini okur; `filename:` ve `has:` ise tüm yazışmadaki her eki okur, etiketler ve klasörler de tüm yazışmayı okur. Filtresiz listelemenin okuduğu indeksin aynısını daraltır. Mühürlü iletiler hiçbir gövde metni saklamaz; bu yüzden yalnızca göndericileri, alıcıları ve konuları eşleşebilir. Düz bir sözcük, hangi iletiyle gelmiş olursa olsun, konuşmadaki herhangi bir ekin adıyla da eşleşir.
label_idsstr | Sequence[str]
Listelemeyi bu etiketleri taşıyan konuşmalarla sınırlar. Uç nokta virgülle ayrılmış bir dize alır ve istemci bir listeyi ya da bir tuple'ı sizin yerinize tek bir dizede birleştirir. Kaç tane belirteceğinize dair bir sınır yoktur.
limitint
Kaç ileti dizisinin döndürüleceği, 1 ile 100 arasında. Atlandığında işleyici 25 kullanır. Varsayılan, şemada değil işleyicide yaşar; bu yüzden değerin hiç verilmemesi ile açıkça 25 verilmesi aynı davranır.
cursorstr
Bir önceki sayfanın `nextCursor` değeri, olduğu gibi geri iletilir. Diğer tüm listelerin kullandığı ad altındaki API `pageToken` değeridir ve opaktır; bu yüzden asla kendiniz bir tane oluşturmayın ya da düzenlemeyin.

Yanıt: Page[ThreadSummaryResource]

itemslist[ThreadSummaryResource]
Bu sayfadaki her ileti dizisi için bir girdi; API'nin `data` zarfından çıkarılmıştır. Her girdi yalnızca bir nesne işareti ve bir id'dir. Listeleme konu, özet, katılımcı ya da etiket taşımaz; bu yüzden daha fazlası için istediğiniz ileti dizilerinde `threads.get` çağırmanız gerekir.
items[].idstr
İleti dizisinin id'si; `threads.get`, `threads.update` ve diğerlerine olduğu gibi verilir. Satır ister filtrelenmiş bir listelemeden ister bir `query` aramasından gelsin, id aynıdır.
hasMorebool
Başka bir sayfa olup olmadığı; API bunu bildirmediğinde `nextCursor`'dan türetilir.
nextCursorstr | None
API'nin `nextPageToken` değeri; sonraki sayfa için `cursor` olarak geri gönderilir ya da başka sayfa yoksa `None` olur. Boş bir token `None` değerine normalleştirilir; böylece falsy denetimi ile `None` denetimi aynı sonucu verir.

Referans