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.smtp.server

import mail

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

The receiving end of SMTP.

SmtpServer accepts connections, runs the ESMTP conversation, and asks handlers of your own what to do at each stage: whether to take this sender, this recipient, this message. It knows the protocol; everything about policy is yours.

import mail.smtp { SmtpServer }

var server = SmtpServer({ port: 2525, hostname: 'mail.example.com' })

server.on_rcpt(@(session, recipient) {
  if !recipient.domain.ends_with('example.com') {
    return { code: 550, message: 'not a local address' }
  }
})

server.on_data(@(session, raw) {
  store.deliver(session.recipients, raw)
})

server.listen()

A handler that returns nothing accepts. One that returns a code and a message refuses, with those. One that raises is a failure on the server’s side, and the sender is told to try again later.

Constants

MECHANISMS

mail.MECHANISMS = [...]

DEFAULT_MAX_SIZE

mail.DEFAULT_MAX_SIZE = 35882577

DEFAULT_MAX_RECIPIENTS

mail.DEFAULT_MAX_RECIPIENTS = 100

MAX_ERRORS

mail.MAX_ERRORS = 10

MAX_DATA_LINE

mail.MAX_DATA_LINE = 4096

Classes

SmtpSession

class mail.SmtpSession

One connection, and everything known about it so far.

Handlers are given this and may put their own values on it through state, which starts empty and lives as long as the connection.

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

Constructor

mail.SmtpSession(peer: string, secure: bool)

sender is the Address the transaction is from, nil before one has started, and an empty string for the null path a bounce comes from. recipients is the Address values accepted so far.

Parameters

  • peer (string) — The address the connection came from.
  • secure (bool) — Whether it is encrypted.

SmtpSession.is_authenticated()

mail.SmtpSession.is_authenticated() -> bool

Whether the client has authenticated.

Returns bool

SmtpSession.is_secure()

mail.SmtpSession.is_secure() -> bool

Whether the connection is encrypted.

Returns bool

SmtpSession.reset()

mail.SmtpSession.reset()

SmtpSession.to_string()

mail.SmtpSession.to_string()

SmtpServer

class mail.SmtpServer

A server that accepts mail.

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

Constructor

mail.SmtpServer(options: ?dict)
optiondefaultwhat it does
host127.0.0.1the address to bind
port25the port to bind
hostnamethe machine’s ownthe name to greet clients with
max_size35 MBthe largest message to take
max_recipients100recipients one message may have
timeout300000milliseconds a client may go quiet
require_tlsfalserefuse mail on an unencrypted connection
require_authfalserefuse mail from a client that has not authenticated
bannernoneextra text on the greeting line

Parameters

  • options (?dict)

SmtpServer.on_connect()

mail.SmtpServer.on_connect(handler) -> SmtpServer

Called when a connection opens, with the session. Refusing here closes the connection before the greeting.

Parameters

  • handler (function(1))

Returns SmtpServer — itself.

SmtpServer.on_mail()

mail.SmtpServer.on_mail(handler) -> SmtpServer

Called with the session and the sender Address when a transaction starts.

Parameters

  • handler (function(2))

Returns SmtpServer — itself.

SmtpServer.on_rcpt()

mail.SmtpServer.on_rcpt(handler) -> SmtpServer

Called with the session and each recipient Address. This is where a server decides whether it has anywhere to put the message.

Parameters

  • handler (function(2))

Returns SmtpServer — itself.

SmtpServer.on_data()

mail.SmtpServer.on_data(handler) -> SmtpServer

Called with the session and the message, as bytes, once the whole of it has arrived. This is where a message is delivered.

Parameters

  • handler (function(2))

Returns SmtpServer — itself.

SmtpServer.on_auth()

mail.SmtpServer.on_auth(handler) -> SmtpServer

Called with the session and { mechanism, username, password }. Returning nothing accepts.

Without this handler the server advertises no authentication at all, and a client that tries anyway is told so.

Parameters

  • handler (function(2))

Returns SmtpServer — itself.

SmtpServer.on_password()

mail.SmtpServer.on_password(handler) -> SmtpServer

Called with a username, and returns that account’s password or nil.

CRAM-MD5 proves the password without sending it, which means the server has to work out the same digest and therefore has to know the password. A server that cannot supply one does not offer the mechanism.

Parameters

  • handler (function(1))

Returns SmtpServer — itself.

SmtpServer.on_close()

mail.SmtpServer.on_close(handler) -> SmtpServer

Called with the session when a connection closes, however it closed.

Parameters

  • handler (function(1))

Returns SmtpServer — itself.

SmtpServer.on_error()

mail.SmtpServer.on_error(handler) -> SmtpServer

Called with the error and the session when something inside the server fails. Without it, failures are silent and the client is told to try again later.

Parameters

  • handler (function(2))

Returns SmtpServer — itself.

SmtpServer.use_tls()

mail.SmtpServer.use_tls(cert_chain: string, private_key: string) -> SmtpServer

Gives the server a certificate, which is what lets it offer STARTTLS.

Parameters

  • cert_chain (string) — The certificate chain, PEM encoded.
  • private_key (string) — The key, PEM encoded.

Returns SmtpServer — itself.

SmtpServer.set_tls_config()

mail.SmtpServer.set_tls_config(config) -> SmtpServer

Gives the server a TLS configuration built elsewhere.

Parameters

  • config (TlsConfig)

Returns SmtpServer — itself.

SmtpServer.is_secure()

mail.SmtpServer.is_secure() -> bool

Whether the server can offer STARTTLS.

Returns bool

SmtpServer.bind()

mail.SmtpServer.bind() -> SmtpServer

Binds the listening socket without accepting anything yet, so that the address is known before the first connection.

Returns SmtpServer — itself.

SmtpServer.address()

mail.SmtpServer.address() -> SocketAddr

The address the server is listening on, which is how a port of 0 is turned into the one the system chose.

Returns SocketAddr

SmtpServer.accept()

mail.SmtpServer.accept() -> SmtpServer

Accepts one connection and serves it to the end.

Returns SmtpServer — itself.

SmtpServer.listen()

mail.SmtpServer.listen() -> SmtpServer

Accepts connections one after another until close().

One connection is served at a time. To serve several at once, run serve() instead, which puts a pool of isolates behind the same socket.

Returns SmtpServer — itself.

SmtpServer.close()

mail.SmtpServer.close() -> SmtpServer

Stops the accept loop and closes the listening socket.

Returns SmtpServer — itself.

SmtpServer.is_listening()

mail.SmtpServer.is_listening() -> bool

Whether the accept loop is running.

Returns bool

SmtpServer.serve_connection()

mail.SmtpServer.serve_connection(client) -> SmtpServer

Serves one already-accepted connection to the end, then closes it.

This is the whole conversation: the greeting, every command, and the close. Call it directly to put a server behind a socket something else accepted.

Parameters

  • client (TcpStream)

Returns SmtpServer — itself.

SmtpServer.to_string()

mail.SmtpServer.to_string()

2026, Richard Ore and Zuri contributors