kilter.service.session module
Sessions are the kernel of a filter, providing it with an async API to access messages
- exception Aborted[source]
Bases:
BaseException
An exception for aborting filters on receipt of an Abort message
- class Filter(*args, **kwargs)[source]
Bases:
Protocol
Filters are callables that accept a
Session
and return a response
- class Phase(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
-
Session phases indicate what messages to expect and are impacted by received messages
Users should not generally need to use these values, however an understanding of the state-flow they represent is useful for understanding some error exception raised by
Session
methods.- CONNECT = 1
This phase is the starting phase of a session, during which a HELO/EHLO message may be awaited with
Session.helo()
.
- MAIL = 2
This phase is entered after HELO/EHLO, during which a MAIL message may be awaited with
Session.envelope_from()
. TheSession.extension()
method may also be used to get the raw MAIL command with any extension arguments, or any other extension commands that the MTA does not support (if the MTA supports passing these commands to a filter).
- ENVELOPE = 3
This phase is entered after MAIL, during which any RCPT commands may be awaited with
Session.envelope_recipients()
. TheSession.extension()
method may also be used to get the raw RCPT command with any extension arguments, or any other extension commands that the MTA does not support (if the MTA supports passing these commands to a filter).
- HEADERS = 4
This phase is entered after a DATA command, while message headers are processed. Headers may be iterated as they arrive, or be collected for later through the
Session.headers
object.
- BODY = 5
This phase is entered after a message’s headers have been processed. The raw message body may be iterated over in chunks through the
Session.body
object.
- POST = 6
This phase is entered once a message’s body has been completed (or skipped). During this phase the message editing methods of a
Session
object or theSession.headers
andSession.body
objects may be used.
- class Position(subject: Union[Header, Literal['start'], Literal['end']])[source]
Bases:
object
A base class for
Before
andAfter
, this class is not intended to be used directly
- class Before(subject: Header)[source]
Bases:
Position
Indicates a relative position preceding a subject
Header
in a header list- subject: Header
- class After(subject: Header)[source]
Bases:
Position
Indicates a relative position following a subject
Header
in a header list- subject: Header
- START = Position(subject='start')
Indicates the start of a header list, before the first (current) header
- END = Position(subject='end')
Indicates the end of a header list, after the last (current) header
- class Session(connmsg: Connect, sender: AsyncGenerator[None, kilter.service.session.EditMessage], broadcast: Optional[Broadcast[kilter.service.session.EventMessage]] = None)[source]
Bases:
object
The kernel of a filter, providing an API for filters to access messages from an MTA
- host: str
A hostname from a reverse address lookup performed when a client connects
If no name is found this value defaults to the standard presentation format for
Session.address
surrounded by “[” and “]”, e.g. “[192.0.2.100]”
- address: ipaddress.IPv4Address | ipaddress.IPv6Address | pathlib.Path | None
The address of the connected client, or None if unknown
- macros: dict[str, str]
A mapping of string replacements sent by the MTA
See smfi_getsymval from libmilter for more information.
Warning
The current implementation is very naïve and does not behave exactly like libmilter, nor is it very robust. It will definitely change in the future.
- headers: HeadersAccessor
A
HeadersAccessor
object for accessing and modifying the message header fields
- body: BodyAccessor
A
BodyAccessor
object for accessing and modifying the message body
- async deliver(message: kilter.service.session.EventMessage) type[kilter.protocol.messages.Continue] | type[kilter.protocol.messages.Skip] [source]
Deliver a message (or its contents) to a task waiting for it
- async envelope_from() str [source]
Wait for a MAIL command message and return the sender identity
Note that if extensions arguments are wanted, users should use
Session.extension()
instead with a name of"MAIL"
.
- async envelope_recipients() AsyncIterator[str] [source]
Wait for RCPT command messages and iteratively yield the recipients’ identities
Note that if extensions arguments are wanted, users should use
Session.extension()
instead with a name of"RCPT"
.
- async extension(name: str) memoryview [source]
Wait for the named command extension and return the raw command for processing
- async change_sender(sender: str, args: str = '') None [source]
Move onto the
Phase.POST
phase and instruct the MTA to change the sender address
- async add_recipient(recipient: str, args: str = '') None [source]
Move onto the
Phase.POST
phase and instruct the MTA to add a new recipient address
- async remove_recipient(recipient: str) None [source]
Move onto the
Phase.POST
phase and instruct the MTA to remove a recipient address
- class HeadersAccessor(session: Session, sender: AsyncGenerator[None, kilter.service.session.EditMessage])[source]
Bases:
AsyncContextManager
[HeaderIterator
]A class that allows access and modification of the message headers sent from an MTA
To access headers (which are only available iteratively), use an instance as an asynchronous context manager; a
HeaderIterator
is returned when the context is entered.- async collect() None [source]
Collect all headers without producing an iterator
Calling this method before the
Phase.BODY
phase allows later processing of headers (after the HEADER phase) without the need for an empty loop.
- async delete(header: Header) None [source]
Move onto the
Phase.POST
phase and Instruct the MTA to delete the given header
- async update(header: Header, value: bytes) None [source]
Move onto the
Phase.POST
phase and Instruct the MTA to modify the value of a header
- class HeaderIterator(aiter: AsyncGenerator[Header, None])[source]
Bases:
AsyncGenerator
[Header
,None
]Iterator for headers obtained by using a
HeadersAccessor
as a context manager- async asend(value: None = None) Header [source]
Send a value into the asynchronous generator. Return next yielded value or raise StopAsyncIteration.
- async athrow(e: type[BaseException] | BaseException, m: object = None, t: types.TracebackType | None = None, /) Header [source]
Raise an exception in the asynchronous generator. Return next yielded value or raise StopAsyncIteration.
- async restrict(*names: str) AsyncIterator[Header] [source]
Return an asynchronous generator that filters headers by name
- class BodyAccessor(session: Session, sender: AsyncGenerator[None, kilter.service.session.EditMessage])[source]
Bases:
AsyncContextManager
[AsyncIterator
[memoryview
]]A class that allows access and modification of the message body sent from an MTA
To access chunks of a body (which are only available iteratively), use an instance as an asynchronous context manager; an asynchronous iterator is returned when the context is entered.
- async write(chunk: bytes) None [source]
Request that chunks of a new message body are sent to the MTA
This method should not be called from within the scope created by using it’s instance as an async context (async with); doing so may cause a warning to be issued and the rest of the message body to be skipped.