Yandex Mail
@magistr/yandex-mailv2026.10.25.10
01README
Yandex Mail over IMAP (read, search, organise) and SMTP (send). Yandex has no JMAP or public REST mail API, so this speaks the standard protocols with an app password of type Mail or an OAuth token (XOAUTH2).
Methods:
get-account-summary,list-mailboxes— folders with total/unread countscreate-mailbox,rename-mailbox,delete-mailbox— idempotent folder opsquery-emails— search a mailbox (date, from, to, subject, text, unread, flagged), newest firstget-email,get-thread,get-attachment— decoded body, conversation via Message-ID/References, save an attachment to disksend-email,reply-email,forward-email,create-draft,send-draft— SMTP sending with optional idempotentmessageIdarchive-mailbox— incremental Maildir backup (raw .eml per message)import-apple-mail— fill server-unavailable messages from Apple Mail's cacheset-email,archive-email,delete-email,bulk-email-action— flags, moves, trash/spam, permanent delete
Emails are addressed as <mailbox>:<uid> (e.g. INBOX:1234).
02Release Notes
2026.10.25.10
- Repo-wide republish; no functional change.
03Behaviors
@magistr/yandex-mailv2026.10.25.10extensions/models/yandex_mail.ts
Global Arguments
| Argument | Type | Description |
|---|---|---|
| username | string | Yandex login or full address (e.g. user@yandex.ru). A bare login is |
| appPassword? | string | App password of type Mail (Yandex ID → Security → App passwords) |
| oauthToken? | string | OAuth token with mail scope, used via XOAUTH2 instead of appPassword |
| fromName? | string | Display name for sent mail |
| imapHost? | string | IMAP host (imap.ya.ru is the alternative outside Russia) |
| smtpHost? | string | SMTP host |
| smtpPort? | number | SMTP port: 465 (implicit TLS) or 587 (STARTTLS) |
fn get-account-summary()
Account overview with total/unread counts per mailbox
fn list-mailboxes()
List all mailboxes (folders) with message counts
fn create-mailbox()
Create a mailbox (folder). No-op if it already exists.
fn rename-mailbox()
Rename (move) a mailbox
fn delete-mailbox()
Delete a mailbox and ALL messages in it. No-op if it does not exist.
fn query-emails(after?: string, before?: string, from?: string, to?: string, subject?: string, text?: string, unseen?: boolean, flagged?: boolean, limit?: number)
Search a mailbox (default INBOX) and return newest-first summaries
| Argument | Type | Description |
|---|---|---|
| after? | string | On/after date (ISO 8601) |
| before? | string | Before date (ISO 8601) |
| from? | string | |
| to? | string | |
| subject? | string | |
| text? | string | Search headers and body |
| unseen? | boolean | true = only unread |
| flagged? | boolean | |
| limit? | number |
fn get-email(maxBodyChars?: number, markRead?: boolean)
Get one email with decoded text/HTML and attachment list
| Argument | Type | Description |
|---|---|---|
| maxBodyChars? | number | |
| markRead? | boolean | Set \\Seen after reading (fetching never sets it by itself) |
fn get-thread(mailboxes?: array)
Reconstruct a conversation from Message-ID/References across the
| Argument | Type | Description |
|---|---|---|
| mailboxes? | array | Mailboxes to search (default: the email's mailbox + Sent) |
fn get-attachment(index?: number, filename?: string, outputDir: string)
Save one attachment of an email to a local directory
| Argument | Type | Description |
|---|---|---|
| index? | number | Attachment index from get-email |
| filename? | string | Or match by filename |
| outputDir | string | Directory to write the file into |
fn archive-mailbox(outputDir: string, mailboxes?: array, exclude?: array, maxMessages?: number, batchSize?: number, retryUnavailable?: boolean)
Incrementally back up folders to a local Maildir (raw .eml per
| Argument | Type | Description |
|---|---|---|
| outputDir | string | Maildir root, e.g. ./yandex-backup |
| mailboxes? | array | Folders to archive (default: every selectable folder) |
| exclude? | array | Folders to skip, e.g. ["Spam", "Trash"] |
| maxMessages? | number | Stop after this many fetch attempts in this run (0 = no limit); |
| batchSize? | number | |
| retryUnavailable? | boolean | Fetch UIDs from unavailable.json again instead of skipping them |
fn import-apple-mail(outputDir: string, accountDir: string, envelopeIndex?: string)
Fill the Maildir gaps listed in unavailable.json from Apple Mail's
| Argument | Type | Description |
|---|---|---|
| outputDir | string | Maildir root used by archive-mailbox |
| accountDir | string | Apple Mail account directory, e.g. |
| envelopeIndex? | string | Path to Mail's Envelope Index (default: <accountDir>/../MailData/ |
fn send-email(subject: string, text?: string, html?: string, attachments?: array, inReplyTo?: string, references?: array, messageId?: string, saveToSent?: boolean)
Compose and send an email over SMTP
| Argument | Type | Description |
|---|---|---|
| subject | string | |
| text? | string | Plain-text body |
| html? | string | HTML body |
| attachments? | array | Local file paths to attach |
| inReplyTo? | string | |
| references? | array | |
| messageId? | string | Stable Message-ID. If set and already in Sent, the send is skipped |
| saveToSent? | boolean | Append a copy to Sent. Leave false if Yandex already files SMTP mail |
fn reply-email(text: string, html?: string, replyAll?: boolean, quote?: boolean, messageId?: string, saveToSent?: boolean)
Reply (or reply-all) to an email, quoting the original
| Argument | Type | Description |
|---|---|---|
| text | string | Reply body (plain text) |
| html? | string | |
| replyAll? | boolean | |
| quote? | boolean | Quote the original text |
| messageId? | string | Stable Message-ID for idempotent retries |
| saveToSent? | boolean |
fn forward-email(text?: string, messageId?: string, saveToSent?: boolean)
Forward an email; the original is attached as message/rfc822
| Argument | Type | Description |
|---|---|---|
| text? | string | Note above the forward |
| messageId? | string | |
| saveToSent? | boolean |
fn create-draft(subject: string, text?: string, html?: string, attachments?: array, inReplyTo?: string, references?: array, messageId?: string, saveToSent?: boolean)
Save an email to Drafts without sending
| Argument | Type | Description |
|---|---|---|
| subject | string | |
| text? | string | Plain-text body |
| html? | string | HTML body |
| attachments? | array | Local file paths to attach |
| inReplyTo? | string | |
| references? | array | |
| messageId? | string | Stable Message-ID. If set and already in Sent, the send is skipped |
| saveToSent? | boolean | Append a copy to Sent. Leave false if Yandex already files SMTP mail |
fn send-draft(saveToSent?: boolean)
Send a saved draft, then remove it from Drafts
| Argument | Type | Description |
|---|---|---|
| saveToSent? | boolean |
fn set-email(seen?: boolean, flagged?: boolean)
Set read/flagged state and/or move one email
| Argument | Type | Description |
|---|---|---|
| seen? | boolean | |
| flagged? | boolean |
fn archive-email(emailIds: array)
Mark emails read and move them to Archive
| Argument | Type | Description |
|---|---|---|
| emailIds | array |
fn delete-email(emailIds: array)
Permanently delete (expunge) one or more emails
| Argument | Type | Description |
|---|---|---|
| emailIds | array |
fn bulk-email-action(emailIds: array, action: enum)
Batch action on many emails: mark-read, mark-unread, flag, unflag,
| Argument | Type | Description |
|---|---|---|
| emailIds | array | |
| action | enum |
Resources
mailboxes(30m)— Mailbox (folder) listing with message counts
mailboxResult(infinite)— Mailbox create/rename/delete result
summary(30m)— Account overview: totals and unread per mailbox
emails(15m)— Email query results / bulk action results
email(1h)— Single email with decoded body and attachment list
thread(1h)— Conversation reconstructed from Message-ID/References
attachment(infinite)— Attachment saved to local disk
sendResult(infinite)— Email send result
archive(infinite)— Maildir archive run: per-folder counts and UID watermarks
appleImport(infinite)— Apple Mail cache import: per-folder imported/partial/missing
draft(infinite)— Draft saved to the Drafts mailbox
04Previous Versions
2026.10.25.1MIT
2026.10.25.1
Security
- Update
postal-mime3.0.0 → 4.1.4 for GHSA-f2hq-32vh-53cc (HIGH): decoding a header with many RFC 2047 encoded words took quadratic CPU time, so one large message could stall the event loop. - Update
nodemailer10.0.10 → 10.2.1 for GHSA-85x2-q946-cp5h, GHSA-8c8m-p3m8-cjg8 and GHSA-m943-m63m-w62w (MEDIUM): address-parser bugs that could turn quoted text or comments into recipients.
No schema change.
2026.10.15.9MIT
2026.10.15.9
Changed
- Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.8MIT
2026.10.15.8
Changed
- Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.6MIT
2026.10.15.6
Changed
- Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.5MIT
2026.10.15.5
Changed
- Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.4MIT
2026.10.15.4
Changed
- Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.3MIT
2026.10.15.3
Changed
- Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.2MIT
2026.10.15.2
Changed
- Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.1MIT
2026.10.15.1
Changed
- Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.11.1MIT
2026.10.11.1
First release.
- Yandex Mail over IMAP (imap.yandex.com:993, TLS) and SMTP (465 implicit TLS or 587 STARTTLS), with an app password of type Mail or an OAuth token (XOAUTH2).
- Mailboxes:
get-account-summary,list-mailboxes, and idempotentcreate-mailbox,rename-mailbox,delete-mailbox(INBOX and special-use folders are never deleted). - Reading:
query-emails,get-email,get-thread,get-attachment. - Sending:
send-email,reply-email,forward-email,create-draft,send-draft. AmessageIdmakes a send idempotent: if that Message-ID is already in Sent, the send is skipped. - Organising:
set-email,archive-email,delete-email,bulk-email-action. - Backup:
archive-mailboxwrites an incremental Maildir and records messages the server cannot deliver inunavailable.json;import-apple-mailfills those gaps from Apple Mail's local cache.
Fixed before release
Found while writing the test suites:
archive-mailboxmaxMessagessubtracted every UID already listed as unavailable from the budget, so a folder with old unavailable messages used up the budget of the folders after it. The budget now counts only the fetch attempts made in the current run.reply-emailcrashed with a TypeError when the original had a Reply-To but no From header and quoting was on.- A message with an unparseable Date header made
query-emailsandget-threadfail withRangeError: Invalid time value. The date now falls back to INTERNALDATE, then to "". - Email ids with a non-decimal UID (
INBOX:1e3,INBOX:0x10,INBOX: 1) or a UID above 2^32-1 were accepted. They are now rejected. get-thread,get-email,get-attachmentandset-emailon two folders with non-ASCII (for example Cyrillic) names and the same UID wrote the same resource name, so the second overwrote the first. Non-ASCII ids now get a short hash suffix; ASCII ids keep their names.- A
messageIdcontaining CR/LF or spaces was folded into a malformed Message-ID header and broke the idempotency lookup. It is now rejected, anda@b>no longer becomes<a@b>>. - An attachment named
.,.., or an empty name madeget-attachmentwrite to the output directory path itself. Such names, and control characters, are now replaced. - Mailbox arguments and email ids with CR, LF or NUL are rejected before any IMAP connection is opened.
- Error messages are scrubbed of the app password and OAuth token.
Internal
transportexport: the factories that build the IMAP client and SMTP transport. Tests replace them with in-memory fakes.
05Stats
A
100 / 100
Downloads
16
Archive size
643.8 KB
- Has README or module doc2/2earned
- README has a code example1/1earned
- README is substantive1/1earned
- Most symbols documented1/1earned
- No slow types (deprecated)1/1earned
- Dependencies pass trust audit2/2earned
- Docs keep secrets in a vault1/1earned
- Has description1/1earned
- Platform support declared (or universal)2/2earned
- License2/2earned
- Verified public repository2/2earned
Repository
https://github.com/umag/swamp-workspace06Platforms
07Labels