mail.stream
import mail
mail.stream, soimport mailis enough and the names are called asmail.stream.*.import mail.streamreaches the same definitions directly.
A line-oriented connection, which is what all three mail protocols are underneath.
SMTP, IMAP and POP3 all speak in lines ending with a carriage return and
a newline, mixed with runs of raw bytes whose length something else
announced. LineStream puts that over any of the transports net
provides, and lets one be swapped for another mid-conversation, which is
what STARTTLS is.
Constants
TLS_MODES
mail.stream.TLS_MODES: list = [...]
How TLS is treated on a connection that did not start encrypted:
require refuses to go on without it, prefer takes it when the server
offers it, and disable does not ask.
MAX_LINE
mail.stream.MAX_LINE = 65536
Functions
connect()
mail.stream.connect(host: string, port: number, options: dict) -> LineStream
Opens a connection to a host, in TLS or in the clear.
Parameters
host(string)port(number)options(dict) —timeoutin milliseconds,tlsto handshake immediately,tls_configandserver_name.
Returns LineStream
Raises Error if the connection or the handshake fails.
start_tls()
mail.stream.start_tls(stream, server_name: string, config) -> LineStream
Wraps a connection that started in the clear in TLS, which is what every
STARTTLS comes down to.
Parameters
stream(LineStream)server_name(string) — The name to check the certificate against.config(?TlsConfig)
Returns LineStream — the same one, now encrypted.
Raises Error if the handshake fails.
endpoint()
mail.stream.endpoint(url: string, schemes: dict) -> dict
Reads a connection string into the pieces needed to open it.
Accepts scheme://[user[:password]@]host[:port], and a bare
host[:port] for which the first scheme in schemes is assumed.
import mail.stream
var where = stream.endpoint('smtps://ann:secret@mail.example.com', {
smtp: { port: 587, tls: false },
smtps: { port: 465, tls: true },
})
echo '${where.host} ${where.port} ${where.tls} ${where.username}'
mail.example.com 465 true ann
Parameters
url(string)schemes(dict) — Each scheme’s default port and whether it means TLS from the first byte.
Returns dict — of scheme, host, port, tls, username and
password, the last two nil when the string carries none.
Raises ProtocolError if the scheme is not one of those given, or
there is no host.
Classes
LineStream
class mail.stream.LineStream
A connection that reads and writes lines.
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
mail.stream.LineStream(transport, secure: ?bool)
Parameters
transport(any) — Anything withread(),write_all(),flush()andclose(). Every socket innetqualifies.secure(?bool) — Whether the transport is already encrypted. Worked out from the transport when not given.
LineStream.transport()
mail.stream.LineStream.transport() -> any
The transport underneath, for the calls this does not wrap.
Returns any
LineStream.is_secure()
mail.stream.LineStream.is_secure() -> bool
Whether what goes over this connection is encrypted.
Returns bool
LineStream.upgrade()
mail.stream.LineStream.upgrade(transport, secure: ?bool) -> LineStream
Replaces the transport with another, which is what a protocol does once it has negotiated TLS over a connection that started in the clear.
Parameters
transport(any)secure(?bool)
Returns LineStream — itself.
Raises ProtocolError if anything is still buffered, since bytes
read before the handshake cannot belong after it.
LineStream.read_line()
mail.stream.LineStream.read_line(limit: ?number) -> string
Reads one line.
The line break comes off, and a lone newline is accepted in place of the pair, because servers send one often enough that refusing would be refusing real mail.
Parameters
limit(?number) — The longest line to accept.MAX_LINEwhen not given.
Returns string
Raises ConnectionClosed if the connection ends mid-line.
Raises ProtocolError if the line runs past the limit.
LineStream.read_bytes()
mail.stream.LineStream.read_bytes(count: number) -> bytes
Reads exactly count bytes, whatever they contain.
Parameters
count(number)
Returns bytes
Raises ConnectionClosed if the connection ends first.
LineStream.has_buffered()
mail.stream.LineStream.has_buffered() -> bool
Whether anything is waiting in the buffer, without touching the transport.
Returns bool
LineStream.write()
mail.stream.LineStream.write(data) -> LineStream
Writes bytes as they are.
Parameters
data(string|bytes)
Returns LineStream — itself.
LineStream.write_line()
mail.stream.LineStream.write_line(text: string) -> LineStream
Writes one line and the break that ends it.
Parameters
text(string)
Returns LineStream — itself.
LineStream.flush()
mail.stream.LineStream.flush() -> LineStream
Pushes anything buffered by the transport out to the peer.
Returns LineStream — itself.
LineStream.close()
mail.stream.LineStream.close() -> LineStream
Closes the connection. Closing one that is already closed does nothing.
Returns LineStream — itself.
LineStream.is_closed()
mail.stream.LineStream.is_closed() -> bool
Whether close() has been called.
Returns bool
LineStream.to_string()
mail.stream.LineStream.to_string()
2026, Richard Ore and Zuri contributors