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

import mail

Mail, from the message to the socket.

mail builds and reads messages, and speaks the three protocols that move them: SMTP to send, IMAP and POP3 to read. It also runs the other end, with an SMTP server that accepts mail and an IMAP server that serves it. All of it is written in Zuri.

import mail

var note = mail.message()
  .set_from('reports@example.com')
  .add_to('ann@example.com')
  .set_subject('Quarterly report')
  .set_text('The numbers are in.')

mail.send('smtp://mail.example.com', note, {
  username: 'reports',
  password: secret,
})

What is here

message()starts a message, built up one call at a time
parse()reads one back
send()sends one, opening and closing the connection
Messagea message, or one part of one
Addressone address and the name written with it
Headersthe header block, in order and case-insensitive
SmtpClienta connection to a server that sends mail
ImapClienta connection to a server that stores it
Pop3Clientthe older way of collecting it
SmtpServerthe receiving end of SMTP
ImapServerthe serving end of IMAP
MailStorewhere an ImapServer keeps mail
MailErrorthe root of every error raised here

Reading mail

import mail

var inbox = mail.imap('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()

Running a server

The servers are the same shape as http.HttpServer: bind, listen, and hand each connection to a worker. An SmtpServer decides what to accept through handlers, and an ImapServer answers from a MailStore, of which two ship: one on disk in Maildir format and one in memory.

Security

Every client can start in TLS or negotiate it with STARTTLS, and refuses to send credentials over a connection that is neither. mail.dkim signs outgoing mail and verifies incoming mail.

The mail API

Every public name in mail, wherever it is declared. Each links to the page that documents it.

NameKindSummary
mail.ALLOWED_FLAGSconstant
mail.AddressclassOne address, with the display name that was written alongside it.
mail.AttachmentclassSomething a message carries alongside what it says: a file to offer, or an image the HTML shows.
mail.AuthenticationErrorclassThe credentials were not accepted, or no mechanism both ends understand was on offer.
mail.BASE_CAPABILITIESconstant
mail.BodyPartclassWhat one message is made of, without fetching it: the type of each part, its size, and where in the message…
mail.ConnectionClosedclassThe connection closed while a conversation was still going on, or a command was issued on one that had…
mail.ContentDispositionclassWhat a part is for: shown where it sits, or offered as a file.
mail.ContentTypeclassA media type and the parameters that came with it.
mail.DEFAULT_CHARSETconstant
mail.DEFAULT_MAX_RECIPIENTSconstant
mail.DEFAULT_MAX_SIZEconstant
mail.DEFAULT_TIMEOUTconstant
mail.DEFAULT_TYPEconstant
mail.DELIMITERconstant
mail.EntryclassOne message in the mailbox, as list() reports it.
mail.EnvelopeclassThe addresses and dates out of a message’s headers, as the server parsed them, so a list of messages can be…
mail.GroupclassA named group of addresses, as Managers: ann@example.com, bob@example.com; writes one.
mail.HeadersclassThe headers of a message or of one of its parts.
mail.IMAP_SCHEMESconstant
mail.INDEX_FILEconstant
mail.INFO_SEPARATORconstant
mail.ImapClientclassA connection to a server that stores mail.
mail.ImapErrorclassThe IMAP server answered a command with NO or BAD.
mail.ImapServerclassA server that serves mail.
mail.ImapSessionclassOne connection, and what it has got as far as doing.
mail.MAILDIR_FLAGSconstant
mail.MAILDIR_PARTSconstant
mail.MAX_DATA_LINEconstant
mail.MAX_ERRORSconstant
mail.MAX_REPLY_LINEconstant
mail.MECHANISMSconstant
mail.MailErrorclassBase class for every error this module raises.
mail.MailStoreclassWhat a store has to be able to do.
mail.MailboxclassAn open mailbox, and what the server said about it when it opened.
mail.MailboxErrorclassSomething went wrong in a mail store: a mailbox that does not exist, one that cannot be created, a message…
mail.MailboxInfoclassOne mailbox as list() reports it: its name, the character that separates the levels of it, and what the…
mail.MaildirStoreclassA store that keeps mail on disk in the Maildir layout.
mail.MemoryStoreclassA store that keeps everything in the process and nothing on disk.
mail.MessageclassOne message, or one part of one.
mail.MessageErrorclassThe bytes handed over are not a message, or are one that contradicts itself: a header with no colon in it, a…
mail.MessageInfoclassWhat a FETCH returned about one message.
mail.POP3_SCHEMESconstant
mail.Pop3ClientclassA connection to a server that hands mail over.
mail.Pop3ErrorclassThe POP3 server answered a command with -ERR.
mail.ProtocolErrorclassThe server said something the protocol does not allow: a greeting that is not a greeting, a response with no…
mail.ReplyclassOne reply from the server: its code, and whatever it said with it.
mail.SMTP_SCHEMESconstant
mail.STATESconstant
mail.SmtpClientclassA connection to a server that sends mail.
mail.SmtpErrorclassThe server rejected a command, and said so with a reply code.
mail.SmtpPermanentErrorclassA 5xx reply: the server will not accept the message, and trying again changes nothing.
mail.SmtpServerclassA server that accepts mail.
mail.SmtpSessionclassOne connection, and everything known about it so far.
mail.SmtpTransientErrorclassA 4xx reply: the server could not accept the message now, and the sender should try again later.
mail.StateErrorclassA command was issued that makes no sense in the state the connection is in: a fetch before a mailbox has been…
mail.StoredMessageclassOne message in a store.
mail.address.addressfunctionBuilds an address without parsing anything.
mail.address.format_listfunctionWrites a list of addresses as a header value.
mail.address.parsefunctionReads exactly one address.
mail.address.parse_groupsfunctionReads every address in a header value, keeping the groups.
mail.address.parse_listfunctionReads every address in a header value.
mail.attachmentfunctionStarts an attachment from what is in it.
mail.dkim.ALGORITHMSconstantThe signing algorithms this implements.
mail.dkim.CANONICALISATIONSconstantThe canonicalisations this implements, on either headers or body.
mail.dkim.DEFAULT_HEADERSconstantThe headers signed when the signer is not told which to sign.
mail.dkim.DkimErrorclassRaised when a signature cannot be built: an algorithm this does not implement, a key that will not parse, a…
mail.dkim.ResultclassWhat checking one signature came to.
mail.dkim.SignatureclassOne DKIM-Signature header, read into its parts.
mail.dkim.SignerclassSigns outgoing messages for one domain with one key.
mail.dkim.canonicalise_bodyfunctionCanonicalises a body.
mail.dkim.canonicalise_headerfunctionCanonicalises one header.
mail.dkim.is_signedfunctionWhether a message carries at least one signature that checks out.
mail.dkim.public_key_pemfunctionTurns the p= value of a key record into a PEM the crypto module will accept.
mail.dkim.verifyfunctionChecks every signature on a message.
mail.encoding.TRANSFER_ENCODINGSconstant
mail.encoding.decode_base64functionDecodes base64, ignoring the line breaks and stray whitespace a message carries it with.
mail.encoding.decode_bodyfunctionDecodes a part’s body the way its Content-Transfer-Encoding says.
mail.encoding.decode_parametersfunctionPuts the parameters of a header back together.
mail.encoding.decode_quoted_printablefunctionDecodes quoted-printable.
mail.encoding.decode_textfunctionTurns bytes into text, reading them as the character set names.
mail.encoding.decode_wordsfunctionReads the encoded words out of a header value and puts back the text they stand for.
mail.encoding.encode_base64functionEncodes data as base64, wrapped into lines.
mail.encoding.encode_bodyfunctionEncodes a part’s body the way its Content-Transfer-Encoding says.
mail.encoding.encode_parameterfunctionWrites one parameter of a header, choosing the form its value needs.
mail.encoding.encode_quoted_printablefunctionEncodes data as quoted-printable.
mail.encoding.encode_wordfunctionEncodes text as one or more RFC 2047 encoded words, so that a header can carry characters a header is not…
mail.encoding.guess_encodingfunctionPicks the transfer encoding a body should use.
mail.encoding.is_asciifunctionWhether every byte is plain ASCII, which decides whether a header or a body needs encoding at all.
mail.format_addressesfunctionWrites a list of addresses as a header value.
mail.headers.ADDRESS_HEADERSconstant
mail.headers.LINE_WIDTHconstant
mail.headers.foldfunctionWrites one header, folded so that no line runs past the width.
mail.headers.unfoldfunction
mail.imapfunctionOpens a connection to a server that stores mail.
mail.messagefunctionStarts a message.
mail.multipartfunction
mail.new_message_idfunctionAn identifier for a message, unique enough that no two ever collide.
mail.parsefunctionReads a message.
mail.parse_addressfunctionReads one address out of text.
mail.parse_address_groupsfunctionReads every address out of text, keeping the groups as groups.
mail.parse_address_listfunctionReads every address out of text, with any groups flattened into their members.
mail.parser.LiteralclassA run of bytes a server sent as a literal.
mail.parser.ReaderclassReads responses off a connection, one at a time.
mail.parser.ResponseclassOne response from the server.
mail.parser.STATUSESconstant
mail.parser.SYSTEM_FLAGSconstant
mail.parser.quotefunctionWrites a value the way a command has to carry it.
mail.parser.tokenizefunctionReads a run of IMAP values out of text.
mail.pool.ClusterclassA running pool: the socket, the workers, and the loop feeding them.
mail.pool.servefunctionStarts a pool and runs it until something closes it.
mail.pool.startfunctionStarts a pool without running the accept loop, so the address is known before the first connection.
mail.pool.worker_mainfunctionWhat one worker isolate runs: build a server of its own, then serve whatever connections the acceptor hands…
mail.pop3functionOpens a connection to a server that hands mail over.
mail.sasl.AnonymousclassANONYMOUS: no identity at all, with an optional note saying who is knocking.
mail.sasl.CramMd5classCRAM-MD5: a keyed digest of the server’s challenge, so the password never travels.
mail.sasl.ExternalclassEXTERNAL: the connection already established who this is, usually with a client certificate.
mail.sasl.LoginclassLOGIN: the username and the password again, one prompt at a time.
mail.sasl.MechanismclassWhat every mechanism looks like from the outside.
mail.sasl.NEEDS_TLSconstantThe mechanisms that put the password itself on the wire, and so must never be used without TLS.
mail.sasl.OAuthBearerclassOAUTHBEARER: the standardised form of the same idea, from RFC 7628.
mail.sasl.PREFERENCEconstantThe mechanisms this implements, strongest first, which is the order a client picks from what a server offers.
mail.sasl.PlainclassPLAIN: the username and the password, separated by zero bytes.
mail.sasl.ScramclassSCRAM-SHA-1 and SCRAM-SHA-256: the password is never sent, the server never has to store it, and the…
mail.sasl.XOAuth2classXOAUTH2: a bearer token rather than a password, which is what Google and Microsoft accept.
mail.sasl.choosefunctionPicks the mechanism to use.
mail.sasl.offunctionBuilds a mechanism by name.
mail.sasl.preparefunctionPrepares a username or password the way RFC 4013 says to, so that two spellings of the same characters…
mail.sasl.responsefunctionThe answer to a CRAM-MD5 challenge.
mail.sendfunctionSends one message, opening the connection and closing it again.
mail.smtpfunctionOpens a connection to a server that sends mail.
mail.stream.LineStreamclassA connection that reads and writes lines.
mail.stream.MAX_LINEconstant
mail.stream.TLS_MODESconstantHow TLS is treated on a connection that did not start encrypted: require refuses to go on without it,…
mail.stream.connectfunctionOpens a connection to a host, in TLS or in the clear.
mail.stream.endpointfunctionReads a connection string into the pieces needed to open it.
mail.stream.start_tlsfunctionWraps a connection that started in the clear in TLS, which is what every STARTTLS comes down to.
mail.text_partfunctionBuilds one text part.

Submodules

ModuleReached asSummary
mail.addressmail.address.*Reading and writing the addresses in a mail header.
mail.contentmail.*The two headers that say what a part holds and what to do with it.
mail.dkimmail.dkim.*DomainKeys Identified Mail: signing outgoing messages so a receiver can tell they came from the domain they…
mail.encodingmail.encoding.*The encodings a message uses to get eight bit data through a seven bit pipe.
mail.errorsmail.*Every error the mail stack raises, under one root.
mail.headersmail.headers.*The header block of a message: what is in it, in what order, and how it is written back out.
mail.imapmail.*IMAP: reading mail where it is kept, rather than taking it away.
mail.messagemail.*A mail message: its headers, its body, and the tree of parts a body turns into once there is more than one…
mail.poolmail.pool.*Running a mail server on more than one connection at a time.
mail.pop3mail.*POP3: the client end of collecting mail.
mail.saslmail.sasl.*The authentication mechanisms all three mail protocols share.
mail.smtpmail.*SMTP: the protocol that moves mail from where it was written to where it is kept.
mail.streammail.stream.*A line-oriented connection, which is what all three mail protocols are underneath.

Functions

parse_address()

mail.parse_address(text: string) -> Address

Reads one address out of text.

import mail

echo mail.parse_address('Ann <ann@example.com>').address
ann@example.com

Parameters

  • text (string)

Returns Address

Raises MessageError if the text holds no address, or several.

parse_address_list()

mail.parse_address_list(text: string) -> list

Reads every address out of text, with any groups flattened into their members.

Parameters

  • text (string)

Returns list — of Address

parse_address_groups()

mail.parse_address_groups(text: string) -> list

Reads every address out of text, keeping the groups as groups.

Parameters

  • text (string)

Returns list — of Address and Group

format_addresses()

mail.format_addresses(people: list) -> string

Writes a list of addresses as a header value.

Parameters

  • people (list) — Address values, Group values, or text to be parsed first.

Returns string

send()

mail.send(url: string, note, options: ?dict) -> Reply

Sends one message, opening the connection and closing it again.

This is the whole of sending mail for a program that sends one at a time. A program sending many wants an SmtpClient of its own, kept open across all of them.

import mail

mail.send('smtp://mail.example.com', mail.message()
  .set_from('reports@example.com')
  .add_to('ann@example.com')
  .set_subject('Quarterly report')
  .set_text('The numbers are in.'),
  { username: 'reports', password: secret })

Parameters

  • url (string) — smtp://host or smtps://host.
  • note (Message)
  • options (?dict) — Everything SmtpClient.connect() takes, and from and to to override the envelope.

Returns Reply — the server’s verdict on the message.

Raises SmtpError if the server refuses any part of it.

smtp()

mail.smtp(url: string, options: ?dict) -> SmtpClient

Opens a connection to a server that sends mail.

Parameters

  • url (string)
  • options (?dict)

Returns SmtpClient

imap()

mail.imap(url: string, options: ?dict) -> ImapClient

Opens a connection to a server that stores mail.

Parameters

  • url (string)
  • options (?dict)

Returns ImapClient

pop3()

mail.pop3(url: string, options: ?dict) -> Pop3Client

Opens a connection to a server that hands mail over.

Parameters

  • url (string)
  • options (?dict)

Returns Pop3Client


2026, Richard Ore and Zuri contributors