mail.imap.client
import mail
Everything here is re-exported by
import mailis enough and the names are called asmail.*. Importingmail.imap.clienton its own works too and reaches the same definitions.
The reading end of IMAP.
ImapClient connects to a server, opens a mailbox, and reads what is in
it. Unlike POP3, nothing is downloaded that was not asked for: a
message’s headers, one part of it, or the whole of it, as needed.
import mail.imap { ImapClient }
var inbox = ImapClient.connect('imaps://mail.example.com', {
username: 'ann',
password: secret,
})
inbox.select('INBOX')
for id in inbox.search('UNSEEN') {
echo inbox.fetch_message(id).subject()
}
inbox.logout()
Constants
IMAP_SCHEMES
mail.IMAP_SCHEMES = {...}
STATES
mail.STATES = [...]
Classes
Mailbox
class mail.Mailbox
An open mailbox, and what the server said about it when it opened.
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
mail.Mailbox(name: string)
Parameters
name(string)
Mailbox.to_string()
mail.Mailbox.to_string()
MailboxInfo
class mail.MailboxInfo
One mailbox as list() reports it: its name, the character that
separates the levels of it, and what the server says about it.
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
mail.MailboxInfo(name: string, flags: list, delimiter: ?string)
Parameters
name(string)flags(list) — The attributes, such as\HasChildren.delimiter(?string) — The hierarchy separator, ornilfor a server with no hierarchy at all.
MailboxInfo.is_selectable()
mail.MailboxInfo.is_selectable() -> bool
Whether the server says this name cannot be selected, which is what a folder that only holds other folders looks like.
Returns bool
MailboxInfo.to_string()
mail.MailboxInfo.to_string()
Envelope
class mail.Envelope
The addresses and dates out of a message’s headers, as the server parsed them, so a list of messages can be shown without fetching any of them.
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
mail.Envelope(values: list)
Envelope.sent_at()
mail.Envelope.sent_at() -> Date|nil
The date as a Date, or nil when the server sent none or it cannot be
read.
Returns Date|nil
Envelope.to_string()
mail.Envelope.to_string()
BodyPart
class mail.BodyPart
What one message is made of, without fetching it: the type of each part, its size, and where in the message it sits.
section is the number a BODY[...] fetch uses to ask for that part on
its own.
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
mail.BodyPart(type: string, subtype: string, parameters: dict, size: ?number, section: string)
Parameters
type(string)subtype(string)parameters(dict)size(?number)section(string)
BodyPart.mime_type()
mail.BodyPart.mime_type() -> string
The media type, as text/plain.
Returns string
BodyPart.walk()
mail.BodyPart.walk() -> list
Every part inside this one and itself, outermost first.
Returns list — of BodyPart
BodyPart.to_string()
mail.BodyPart.to_string()
MessageInfo
class mail.MessageInfo
What a FETCH returned about one message.
Which fields are filled in depends on what was asked for. parts holds
each BODY[...] section that came back, keyed by the section that was
requested.
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
mail.MessageInfo(sequence: number)
Parameters
sequence(number) — The message’s position in the mailbox.
MessageInfo.message()
mail.MessageInfo.message() -> Message|nil
The whole message, when the fetch asked for it.
Returns Message|nil
MessageInfo.is_seen()
mail.MessageInfo.is_seen() -> bool
Whether the message has been read.
Returns bool
MessageInfo.to_string()
mail.MessageInfo.to_string()
ImapClient
class mail.ImapClient
A connection to a server that stores mail.
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
mail.ImapClient(connection, options: ?dict)
Builds a client around a connection that is already open.
Parameters
connection(LineStream)options(?dict) — Asconnect().
ImapClient.connect()
mail.ImapClient.connect(url: string, options: ?dict) -> ImapClient
Opens a connection and gets as far as being able to select a mailbox.
| option | default | what it does |
|---|---|---|
username, password | none | authenticate when both are given |
token | none | authenticate with a bearer token instead |
tls | require | require, prefer or disable, when not already encrypted |
tls_config | a default one | the trust settings for TLS |
mechanisms | all of them | restricts which are acceptable |
timeout | 60000 | milliseconds to wait on the socket |
Parameters
url(string) —imaps://host,imap://host, or a bare host.options(?dict)
Returns ImapClient
Raises ImapError if the server refuses.
Raises AuthenticationError if it refuses the credentials.
ImapClient.begin()
mail.ImapClient.begin() -> ImapClient
Reads the greeting, negotiates TLS and authenticates.
Returns ImapClient — itself.
Raises ImapError if the greeting says the server is not available.
ImapClient.supports()
mail.ImapClient.supports(name: string) -> bool
Whether the server offers a capability.
Parameters
name(string) — Matched without regard to case.
Returns bool
ImapClient.is_secure()
mail.ImapClient.is_secure() -> bool
Whether the connection is encrypted.
Returns bool
ImapClient.refresh_capabilities()
mail.ImapClient.refresh_capabilities() -> list
Asks the server what it can do, replacing what is known.
Returns list — of string
ImapClient.start_tls()
mail.ImapClient.start_tls() -> ImapClient
Negotiates TLS over a connection that started in the clear, and asks what the server can do again, because nothing it said before the handshake was protected.
Returns ImapClient — itself.
Raises ImapError if the server refuses.
ImapClient.login()
mail.ImapClient.login(mechanism: ?string) -> ImapClient
Authenticates, choosing the strongest mechanism both ends know.
A server may forbid a mechanism outright by advertising LOGINDISABLED,
which is how it says the connection is not private enough; this refuses
to try in that case rather than sending the password anyway.
Parameters
mechanism(?string) — Forces one rather than choosing.
Returns ImapClient — itself.
Raises AuthenticationError if there is no mechanism in common or
the credentials are refused.
ImapClient.authenticate()
mail.ImapClient.authenticate(mechanism) -> ImapClient
Runs one authentication exchange with a mechanism already built.
Parameters
mechanism(Mechanism)
Returns ImapClient — itself.
Raises AuthenticationError if the server refuses.
ImapClient.run()
mail.ImapClient.run(name: string, arguments: list) -> list
Sends a command and reads everything it draws, up to and including the tagged answer.
Arguments are written as they are: a plain string goes unquoted, so
quote anything that needs it with parser.quote() first. A Literal is
sent as a literal, waiting for the server’s permission unless it said
permission is not needed.
Parameters
name(string)arguments(list)
Returns list — of the untagged responses the command produced.
Raises ImapError if the server answers NO or BAD.
ImapClient.on_event()
mail.ImapClient.on_event(listener) -> ImapClient
Calls a function with every untagged response the server sends.
This is how a program watches a mailbox: the server announces new mail
and changed flags whenever it likes, and idle() exists so there is
something to announce them during.
Parameters
listener(?function(1)) —nilstops listening.
Returns ImapClient — itself.
ImapClient.select()
mail.ImapClient.select(name: string) -> Mailbox
Opens a mailbox for reading and writing.
Parameters
name(string)
Returns Mailbox
Raises ImapError if there is no such mailbox.
ImapClient.examine()
mail.ImapClient.examine(name: string) -> Mailbox
Opens a mailbox without being able to change anything in it, which also means reading a message does not mark it read.
Parameters
name(string)
Returns Mailbox
Raises ImapError if there is no such mailbox.
ImapClient.close_mailbox()
mail.ImapClient.close_mailbox() -> ImapClient
Closes the open mailbox, removing the messages marked deleted on the way out.
Returns ImapClient — itself.
ImapClient.unselect()
mail.ImapClient.unselect() -> ImapClient
Closes the open mailbox without removing anything, which is what CLOSE
cannot do.
Returns ImapClient — itself.
Raises StateError if the server does not offer UNSELECT.
ImapClient.list()
mail.ImapClient.list(reference: ?string, pattern: ?string) -> list
The mailboxes matching a pattern.
* matches anything including the hierarchy separator, and % matches
anything except it, which is what lists one level.
for box in inbox.list('', '*') {
echo box.name
}
Parameters
reference(?string) — The prefix to search under. Empty when not given.pattern(?string) —*when not given.
Returns list — of MailboxInfo
ImapClient.lsub()
mail.ImapClient.lsub(reference: ?string, pattern: ?string) -> list
The mailboxes matching a pattern that this account is subscribed to.
Parameters
reference(?string)pattern(?string)
Returns list — of MailboxInfo
ImapClient.status()
mail.ImapClient.status(name: string, items: ?list) -> dict
What is in a mailbox without opening it.
echo inbox.status('INBOX', ['MESSAGES', 'UNSEEN'])
Parameters
name(string)items(?list) —MESSAGES,RECENT,UIDNEXT,UIDVALIDITYandUNSEEN. All five when not given.
Returns dict — of the items asked for, by name.
ImapClient.create()
mail.ImapClient.create(name: string) -> ImapClient
Creates a mailbox.
Parameters
name(string)
Returns ImapClient — itself.
Raises ImapError if it exists already or the name is not allowed.
ImapClient.delete()
mail.ImapClient.delete(name: string) -> ImapClient
Deletes a mailbox and everything in it.
Parameters
name(string)
Returns ImapClient — itself.
Raises ImapError if there is no such mailbox.
ImapClient.rename()
mail.ImapClient.rename(from: string, to: string) -> ImapClient
Renames a mailbox.
Parameters
from(string)to(string)
Returns ImapClient — itself.
ImapClient.subscribe()
mail.ImapClient.subscribe(name: string) -> ImapClient
Marks a mailbox as one this account wants to see.
Parameters
name(string)
Returns ImapClient — itself.
ImapClient.unsubscribe()
mail.ImapClient.unsubscribe(name: string) -> ImapClient
Undoes subscribe().
Parameters
name(string)
Returns ImapClient — itself.
ImapClient.search()
mail.ImapClient.search(criteria: string, by_uid: ?bool) -> list
The messages in the open mailbox matching a search.
The criteria are IMAP’s own, which read close to English: 'UNSEEN',
'FROM ann@example.com', 'SINCE 1-Jan-2026 SMALLER 10000'.
for uid in inbox.search('UNSEEN SINCE 1-Jan-2026', true) {
echo uid
}
Parameters
criteria(string)by_uid(?bool) — Return unique identifiers rather than positions, which is what anything that outlives the connection wants.
Returns list — of number
Raises StateError if no mailbox is open.
ImapClient.fetch()
mail.ImapClient.fetch(ids, items: ?string, by_uid: ?bool) -> list
Fetches what the server knows about some messages.
for info in inbox.fetch('1:10', 'ENVELOPE FLAGS', false) {
echo '${info.sequence} ${info.envelope.subject}'
}
Parameters
ids(string|list|number) — A set, as'1:10'or'1,3,5', or a list of numbers, or one number.items(?string) — What to fetch, in IMAP’s own words.ENVELOPE FLAGS INTERNALDATE RFC822.SIZEwhen not given.by_uid(?bool) — Whetheridsare unique identifiers.
Returns list — of MessageInfo
Raises StateError if no mailbox is open.
ImapClient.fetch_message()
mail.ImapClient.fetch_message(id: number, by_uid: ?bool, mark_seen: ?bool) -> Message
Fetches one message whole.
Reading a message this way does not mark it read, because a program that
goes through a mailbox should not change what a person sees when they
next open it. Pass mark_seen to say otherwise, which is what a mail
client showing a message wants.
echo inbox.fetch_message(uid, true, false).subject()
Parameters
id(number)by_uid(?bool)mark_seen(?bool) — Whether to set\Seenon the way.
Returns Message
Raises ImapError if there is no such message.
ImapClient.fetch_headers()
mail.ImapClient.fetch_headers(ids, by_uid: ?bool) -> list
Fetches only the headers of some messages, which is enough to show a list without pulling the bodies across.
Parameters
ids(string|list|number)by_uid(?bool)
Returns list — of MessageInfo, each with parts holding the
header block.
ImapClient.store()
mail.ImapClient.store(ids, action: string, flags: list, by_uid: ?bool) -> list
Changes the flags on some messages.
Parameters
ids(string|list|number)action(string) —FLAGSto replace,+FLAGSto add,-FLAGSto remove. Add.SILENTto any of them to stop the server reporting the result back.flags(list) — The flags, as['\\Seen'].by_uid(?bool)
Returns list — of MessageInfo describing what changed.
ImapClient.add_flags()
mail.ImapClient.add_flags(ids, flags: list, by_uid: ?bool) -> list
Adds flags to some messages, leaving the rest alone.
Parameters
ids(string|list|number)flags(list)by_uid(?bool)
Returns list — of MessageInfo
ImapClient.remove_flags()
mail.ImapClient.remove_flags(ids, flags: list, by_uid: ?bool) -> list
Removes flags from some messages.
Parameters
ids(string|list|number)flags(list)by_uid(?bool)
Returns list — of MessageInfo
ImapClient.mark_seen()
mail.ImapClient.mark_seen(ids, by_uid: ?bool) -> list
Marks messages read.
Parameters
ids(string|list|number)by_uid(?bool)
Returns list — of MessageInfo
ImapClient.mark_deleted()
mail.ImapClient.mark_deleted(ids, by_uid: ?bool) -> list
Marks messages for removal. Nothing goes until expunge().
Parameters
ids(string|list|number)by_uid(?bool)
Returns list — of MessageInfo
ImapClient.copy()
mail.ImapClient.copy(ids, target: string, by_uid: ?bool) -> ImapClient
Copies messages into another mailbox.
Parameters
ids(string|list|number)target(string)by_uid(?bool)
Returns ImapClient — itself.
ImapClient.move()
mail.ImapClient.move(ids, target: string, by_uid: ?bool) -> ImapClient
Moves messages into another mailbox.
Uses the server’s own MOVE where there is one, and otherwise does what
MOVE was invented to replace: copy, mark deleted, expunge.
Parameters
ids(string|list|number)target(string)by_uid(?bool)
Returns ImapClient — itself.
ImapClient.expunge()
mail.ImapClient.expunge() -> list
Removes every message marked deleted in the open mailbox.
Returns list — of number: the positions that went, highest first,
which is the order they have to be applied in.
ImapClient.append()
mail.ImapClient.append(mailbox: string, note, flags: ?list, received) -> ImapClient
Adds a message to a mailbox without sending it anywhere, which is how a sent message gets into the Sent folder.
Parameters
mailbox(string)note(Message|string|bytes)flags(?list) —['\\Seen']is the usual one for a sent message.received(?Date) — The internal date to file it under. The time of arrival when not given.
Returns ImapClient — itself.
ImapClient.idle()
mail.ImapClient.idle(timeout: ?number) -> list
Waits for the server to say something, which is how a program learns about new mail without asking over and over.
Returns when the server reports anything, or when the wait runs out. A server may drop a connection that idles for too long, so even a program with nothing else to do should come back around every twenty minutes or so; RFC 2177 says as much.
inbox.on_event(@(response) {
echo 'server said ${response.name()}'
})
while true {
inbox.idle(1500000)
}
Parameters
timeout(?number) — Milliseconds to wait.1500000, which is twenty-five minutes, when not given.
Returns list — of the untagged responses that arrived.
Raises StateError if the server does not offer IDLE.
ImapClient.noop()
mail.ImapClient.noop() -> list
Asks the server for nothing, which both keeps the connection alive and gives it a chance to report anything that has changed.
Returns list — of the untagged responses that came with it.
ImapClient.namespace()
mail.ImapClient.namespace()
The namespaces this account has: its own, other people’s, and the shared ones.
Returns — list, as the server sent it.
Raises StateError if the server does not offer NAMESPACE.
ImapClient.enable()
mail.ImapClient.enable(names: list) -> ImapClient
Turns on an extension the server offers but does not use until asked,
such as UTF8=ACCEPT.
Parameters
names(list)
Returns ImapClient — itself.
Raises StateError if the server does not offer ENABLE.
ImapClient.id()
mail.ImapClient.id(fields: ?dict) -> dict
Tells the server what this client is, and reads back what the server is. Both sides may say nothing at all.
Parameters
fields(?dict) —name,versionand whatever else is worth saying. A name ofZuriwhen not given.
Returns dict — of what the server said about itself.
ImapClient.logout()
mail.ImapClient.logout() -> ImapClient
Says goodbye and closes the connection.
Returns ImapClient — itself.
ImapClient.close()
mail.ImapClient.close() -> ImapClient
Closes the connection without saying goodbye.
Returns ImapClient — itself.
ImapClient.to_string()
mail.ImapClient.to_string()
2026, Richard Ore and Zuri contributors