mail.pool
import mail
mail.pool, soimport mailis enough and the names are called asmail.pool.*.import mail.poolreaches the same definitions directly.
Running a mail server on more than one connection at a time.
Both servers here serve one connection to the end before taking the
next, which is the right shape for the protocols and the wrong shape for
more than one client. serve() puts a pool of isolates behind one
listening socket: the main isolate accepts, and each worker takes a
connection and sees it through.
import mail.pool
import .my_server
pool.serve(my_server.build, { host: '0.0.0.0', port: 143, workers: 8 })
build is a function in a module of its own, not a closure, because an
isolate resolves a module’s function by name on its own side and cannot
be handed one that closes over anything here.
# my_server.zu
import mail.imap { ImapServer, MaildirStore }
def build() {
var store = MaildirStore('/var/mail')
store.add_account('ann', 'secret')
return ImapServer({}, store)
}
An IMAP connection can be open for hours, so the pool is a ceiling on how many clients can be served at once, not on how fast they are served. Size it accordingly.
Functions
worker_main()
mail.pool.worker_main(connections, build)
What one worker isolate runs: build a server of its own, then serve whatever connections the acceptor hands it.
Called by serve(). It is public because an isolate has to be able to
find it by name.
Parameters
connections(Channel) — Accepted sockets arrive here.build(function(0)) — Returns this worker’s server.
start()
mail.pool.start(build, options: ?dict) -> Cluster
Starts a pool without running the accept loop, so the address is known before the first connection.
Parameters
build(function(0)) — A module’s function returning a server.options(?dict) —host,portandworkers.
Returns Cluster
serve()
mail.pool.serve(build, options: ?dict) -> Cluster
Starts a pool and runs it until something closes it.
Parameters
build(function(0))options(?dict) — Asstart().
Returns Cluster
Classes
Cluster
class mail.pool.Cluster
A running pool: the socket, the workers, and the loop feeding them.
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
mail.pool.Cluster(listener, connections, workers: list)
Parameters
listener(TcpStream)connections(Channel)workers(list) — The isolates serving them.
Cluster.address()
mail.pool.Cluster.address() -> SocketAddr
The address the pool is listening on.
Returns SocketAddr
Cluster.run()
mail.pool.Cluster.run() -> Cluster
Accepts connections and hands them out until close().
Returns Cluster — itself.
Cluster.accept_one()
mail.pool.Cluster.accept_one() -> Cluster
Accepts exactly one connection and hands it to a worker, for a program that wants to drive the loop itself.
Returns Cluster — itself.
Cluster.close()
mail.pool.Cluster.close(timeout: ?number) -> Cluster
Stops accepting, tells the workers there is nothing more coming, and waits for them to finish what they hold.
Parameters
timeout(?number) — Milliseconds to wait for each worker.
Returns Cluster — itself.
Cluster.to_string()
mail.pool.Cluster.to_string()
2026, Richard Ore and Zuri contributors