Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

mail.imap.store

import mail

Everything here is re-exported by mail, so import mail is enough and the names are called as mail.*. Importing mail.imap.store on its own works too and reaches the same definitions.

Where an ImapServer keeps mail.

MailStore is the contract: what a store has to be able to do for the server to answer with it. Two are provided. MaildirStore keeps mail on disk in the Maildir layout, which every other mail tool can read, so a mailbox written here is not trapped here. MemoryStore keeps it in the process and forgets it on exit, which is what a test and an embedded server want.

import mail.imap { ImapServer, MaildirStore }

var store = MaildirStore('/var/mail/ann')

store.add_account('ann', 'secret')

ImapServer({ port: 143 }, store).listen()

A store of your own only has to answer the same calls. Nothing here is required to come from a file.

Constants

MAILDIR_PARTS

mail.MAILDIR_PARTS = [...]

INFO_SEPARATOR

mail.INFO_SEPARATOR

MAILDIR_FLAGS

mail.MAILDIR_FLAGS = {...}

DELIMITER

mail.DELIMITER = '.'

INDEX_FILE

mail.INDEX_FILE = 'zuri-uidlist'

Classes

StoredMessage

class mail.StoredMessage

One message in a store.

  • printable — has a @to_string(), so echo and print() show something useful

Constructor

mail.StoredMessage(uid: number, raw, flags: list, received)

Parameters

  • uid (number) — Unique within its mailbox, and never reused.
  • raw (bytes) — The message exactly as it arrived.
  • flags (list)
  • received (Date) — When the store took it.

StoredMessage.size()

mail.StoredMessage.size() -> number

How large the message is.

Returns number

StoredMessage.has_flag()

mail.StoredMessage.has_flag(flag: string) -> bool

Whether a flag is set.

Parameters

  • flag (string)

Returns bool

StoredMessage.to_string()

mail.StoredMessage.to_string()

MailStore

class mail.MailStore

What a store has to be able to do.

Every method raises here; a store is something that answers them. Both of the ones that ship do, and so can one of your own.

  • printable — has a @to_string(), so echo and print() show something useful

MailStore.authenticate()

mail.MailStore.authenticate(username: string, password: string) -> bool

Whether these credentials name an account.

Parameters

  • username (string)
  • password (string)

Returns bool

MailStore.password_of()

mail.MailStore.password_of(username: string) -> string|nil

The password of an account, for the mechanisms that prove it without sending it, or nil when there is no such account or the store cannot produce one.

A store that keeps only hashed passwords returns nil, and the server then does not offer those mechanisms.

Parameters

  • username (string)

Returns string|nil

MailStore.has_passwords()

mail.MailStore.has_passwords() -> bool

Whether this store can produce a password rather than only check one.

A server offers the mechanisms that prove a password without sending it only when it can work out the same proof, which means knowing the password. A store that keeps only hashes, or that checks credentials somewhere else entirely, says no here and the server stops offering them.

Returns bool

MailStore.mailboxes()

mail.MailStore.mailboxes(username: string) -> list

The mailboxes an account has.

Parameters

  • username (string)

Returns list — of string

MailStore.exists()

mail.MailStore.exists(username: string, mailbox: string) -> bool

Whether a mailbox exists.

Parameters

  • username (string)
  • mailbox (string)

Returns bool

MailStore.create()

mail.MailStore.create(username: string, mailbox: string)

Creates a mailbox.

Parameters

  • username (string)
  • mailbox (string)

Raises MailboxError if it exists already.

MailStore.remove()

mail.MailStore.remove(username: string, mailbox: string)

Removes a mailbox and everything in it.

Parameters

  • username (string)
  • mailbox (string)

Raises MailboxError if there is no such mailbox.

MailStore.rename()

mail.MailStore.rename(username: string, from: string, to: string)

Renames a mailbox.

Parameters

  • username (string)
  • from (string)
  • to (string)

Raises MailboxError if there is no such mailbox, or the new name is taken.

MailStore.messages()

mail.MailStore.messages(username: string, mailbox: string) -> list

Every message in a mailbox, oldest first.

Parameters

  • username (string)
  • mailbox (string)

Returns list — of StoredMessage

Raises MailboxError if there is no such mailbox.

MailStore.append()

mail.MailStore.append(username: string, mailbox: string, raw, flags: ?list, received) -> StoredMessage

Adds a message to a mailbox.

Parameters

  • username (string)
  • mailbox (string)
  • raw (bytes)
  • flags (?list)
  • received (?Date)

Returns StoredMessage

Raises MailboxError if there is no such mailbox.

MailStore.set_flags()

mail.MailStore.set_flags(username: string, mailbox: string, uid: number, flags: list)

Replaces the flags on one message.

Parameters

  • username (string)
  • mailbox (string)
  • uid (number)
  • flags (list)

Raises MailboxError if there is no such message.

MailStore.expunge()

mail.MailStore.expunge(username: string, mailbox: string) -> list

Removes every message in a mailbox marked \Deleted.

Parameters

  • username (string)
  • mailbox (string)

Returns list — of number: the identifiers that went.

MailStore.counters()

mail.MailStore.counters(username: string, mailbox: string) -> dict

What the next message added to a mailbox will be numbered, and how to tell that the numbering has been reset.

Parameters

  • username (string)
  • mailbox (string)

Returns dict — of uidnext and uidvalidity.

MailStore.to_string()

mail.MailStore.to_string()

MemoryStore

class mail.MemoryStore < MailStore

A store that keeps everything in the process and nothing on disk.

Fast, and gone when the program is. This is what a test wants, and what a server embedded in something else wants when the mail it holds is not the point.

import mail.imap { MemoryStore }

var store = MemoryStore()

store.add_account('ann', 'secret')
store.append('ann', 'INBOX', 'From: a@b.com\r\n\r\nhello', nil, nil)

echo store.mailboxes('ann')
echo store.messages('ann', 'INBOX').length()
[INBOX]
1
  • printable — has a @to_string(), so echo and print() show something useful

Constructor

mail.MemoryStore(mailboxes: ?list)

Parameters

  • mailboxes (?list) — The mailboxes every new account starts with. ['INBOX'] when not given.

MemoryStore.add_account()

mail.MemoryStore.add_account(username: string, password: string) -> MemoryStore

Adds an account, with the mailboxes a new account starts with.

Parameters

  • username (string)
  • password (string)

Returns MemoryStore — itself.

MemoryStore.authenticate()

mail.MemoryStore.authenticate(username: string, password: string)

MemoryStore.password_of()

mail.MemoryStore.password_of(username: string)

MemoryStore.has_passwords()

mail.MemoryStore.has_passwords()

MemoryStore.mailboxes()

mail.MemoryStore.mailboxes(username: string)

MemoryStore.exists()

mail.MemoryStore.exists(username: string, mailbox: string)

MemoryStore.create()

mail.MemoryStore.create(username: string, mailbox: string)

MemoryStore.remove()

mail.MemoryStore.remove(username: string, mailbox: string)

MemoryStore.rename()

mail.MemoryStore.rename(username: string, from: string, to: string)

MemoryStore.messages()

mail.MemoryStore.messages(username: string, mailbox: string)

MemoryStore.append()

mail.MemoryStore.append(username: string, mailbox: string, raw, flags: ?list, received)

MemoryStore.set_flags()

mail.MemoryStore.set_flags(username: string, mailbox: string, uid: number, flags: list)

MemoryStore.expunge()

mail.MemoryStore.expunge(username: string, mailbox: string)

MemoryStore.counters()

mail.MemoryStore.counters(username: string, mailbox: string)

MemoryStore.to_string()

mail.MemoryStore.to_string()

MaildirStore

class mail.MaildirStore < MailStore

A store that keeps mail on disk in the Maildir layout.

Each account is a directory under root, holding its INBOX directly and every other mailbox as .Name beside it, which is the Maildir++ arrangement every other mail tool understands. A mailbox written here can be read by anything else, and mail delivered by anything else turns up here.

Flags are kept the Maildir way, as letters at the end of a message’s filename after :2,. A colon cannot appear in a Windows filename, so on Windows the flags follow ;2, instead, which is what mbsync writes there too. A Maildir moved between Windows and any other system keeps its messages but has to have their flags renamed to match.

Mail is on disk; accounts are not. The store asks the program who its users are, either as a password given to add_account() or through set_authenticator(), because where an application keeps its passwords is the application’s business and not a mail library’s.

import mail.imap { MaildirStore }

var store = MaildirStore('/var/mail')

store.add_account('ann', secret)
store.append('ann', 'INBOX', raw, nil, nil)
  • printable — has a @to_string(), so echo and print() show something useful

Constructor

mail.MaildirStore(root: string)

Parameters

  • root (string) — The directory the accounts live under. It is created if it is not there.

MaildirStore.add_account()

mail.MaildirStore.add_account(username: string, password: string) -> MaildirStore

Adds an account with a password this store will check itself, and makes its mail directory if it is not there.

Parameters

  • username (string)
  • password (string)

Returns MaildirStore — itself.

MaildirStore.set_authenticator()

mail.MaildirStore.set_authenticator(checker) -> MaildirStore

Hands credential checking to a function of your own, which is what a program with its own user table wants.

A store with an authenticator can no longer produce a password, so the server stops offering the mechanisms that need one.

Parameters

  • checker (function(2)) — Given a username and a password, returns whether they are right.

Returns MaildirStore — itself.

MaildirStore.authenticate()

mail.MaildirStore.authenticate(username: string, password: string)

MaildirStore.password_of()

mail.MaildirStore.password_of(username: string)

MaildirStore.has_passwords()

mail.MaildirStore.has_passwords()

MaildirStore.mailboxes()

mail.MaildirStore.mailboxes(username: string)

MaildirStore.exists()

mail.MaildirStore.exists(username: string, mailbox: string)

MaildirStore.create()

mail.MaildirStore.create(username: string, mailbox: string)

MaildirStore.remove()

mail.MaildirStore.remove(username: string, mailbox: string)

MaildirStore.rename()

mail.MaildirStore.rename(username: string, from: string, to: string)

MaildirStore.messages()

mail.MaildirStore.messages(username: string, mailbox: string)

MaildirStore.append()

mail.MaildirStore.append(username: string, mailbox: string, raw, flags: ?list, received)

MaildirStore.set_flags()

mail.MaildirStore.set_flags(username: string, mailbox: string, uid: number, flags: list)

MaildirStore.expunge()

mail.MaildirStore.expunge(username: string, mailbox: string)

MaildirStore.counters()

mail.MaildirStore.counters(username: string, mailbox: string)

MaildirStore.to_string()

mail.MaildirStore.to_string()

2026, Richard Ore and Zuri contributors