If we already saved one or more messages that were split out
of a multi-recipient transaction, and then the subsequent save
fails, we would previously leave those earlier messages saved
in the spool and deliver them despite reporting a failure back
to the client.
This commit removes them from the spool and logs a Bounce record
for them.
This is still not an ideal outcome, but it will at least not
send a message for which we haven't claimed responsibility.
message:recipient() may now return an array style table
holding the recipient list, if there is more than a single
recipient on the message.
Since this can be somewhat ambiguous/frustrating to work with,
there is now also a message:recipient_list() that will always
return an array style table, even if it holds just a single
element.
The included helpers have been updated to use `message:recipient_list`.
message:set_recipient() will now optionally accept an array
style table holding the recipient list to be set.
This commit adds a test for exceeding the number of recipients
allowed in a transaction and fleshes out our handling of that
status so that we will immediately try the remaining recipients
of the batch, without delaying the message by eg: 20 minutes
in the default retry parameters.
As part of this, I noticed that we were returning the wrong
smtp status code in our server implementation, so this
commit fixes that up.
This makes a first pass over relaying a batch, with a test
to prove that it worked.
The logic in the smtp client likely needs to be enhanced
to handle hitting recipient-per-transaction limits; tests
for various scenarios need to be added in follow-on commits.
This adds a `batch_handling` parameter that optionally allows splitting
up a recipient batch based on the destination domain.
The system does not yet have any support for correctly delivering such a
batch.
This commit updates the type signatures of some key structures
to allow for the possibility of a Message having multiple recipients:
* Message (continuing from previous commit)
* JsonLogRecord
* MessageInformation
Some logic has been updated to account for multiple recipients,
but critically, nothing in the core will generate them, and none
of the queue management or delivery infrastructure is aware
of recipients beyond the first.
Use the more relaxed form of Name parsing so that domains
with underscores (which are in common use with email) do
not generate an error at runtime when processing spf
include rules.
I can see someone wanting to know the raw physical connection
info at some point, regardless of the adjusted xclient values,
or in the future, the proxy protocol adjusted values.
Hooks up the parsed XCLIENT command to the smtp server.
We support just the address changing attributes; we don't
do anything special with the NAME attribute, and I'd like
to think a lot more about authentication before allowing
messing with the LOGIN attribute.
After applying changes to the metadata in the connection,
take care to re-evaluate the listener parameters and
dynamic parameters so that `via` and `peer` blocks can
match the new configuration.
Finishes up support for these extensions by adding a send-time
check and error for the case where we have 8 bit content and
the appropriate extension is not advertised by the next hop.
A shaping option is provided to bypass this, both to facilitate
testing and as a way to bypass it for situations where the
operator knows best.
closes: https://github.com/KumoCorp/kumomta/issues/327
To facilitate this we need to feed the `AppState` down through
the Router more generally, and expand it to grab a copy of the
http listener parameters.
closes: https://github.com/KumoCorp/kumomta/issues/417
Introduce a couple of error variants that indicate that the
failure was during parsing of a specific named header.
This makes it easier to understand the source of an issue.
This is weird; I can't reproduce the CI failure locally, even with an
updated version of rust, but the diagnostic in CI points to
https://github.com/rust-lang/rust/issues/131114 which suggests that
str::from_ut8 is unstable, but buried within it is the mention that
std::str::from_utf8 is OK to use.
Let's see if this does the job?
When performing a rebuild, we'd build completely new RFC 2045/RFC 2047
mime headers.
However, sometimes there are "load bearing" additional parameters in
the source part that are important to preserve; for example, calendar
invites include a `method=REQUEST` parameter that is important to
pass through in order for the invitation to correctly interface with
the recipients calendar.
This commit adjusts the rebuild logic to merge in any parameters
that we didn't set in the basic rebuild.
This makes the startup behavior consistent with kumod and tsa-daemon,
which can help with "Too many open files" errors in systems without
any explicit tunings for the proxy server.
It is still a good idea to explicitly tune that value up, and it is
something we should put into a systemd unit when we get around to
shipping one of those for the proxy server (#188)
The implementation of these encodings in the data-encoding crate is
overly strict when extraneous/excess padding is used, presenting
problems from the perspective of Postel's law especially in the context
of email: there are base64 encoders widely deployed that can produce
extraneous padding that is otherwise harmless but which will raise an
error from this crate.
This commit works around this by manipulating the encoding context
to remove the padding requirement, as well as the padding, and
decodes the input without padding.
We made the unfortunate choice to emit the `timestamp` and `created`
fields as unix timestamps with no sub-second precision.
This commit causes us to emit the full-resolution timestamps that we
already have as additional event_time and created_time fields
in the JsonLogRecord, without internally duplicating those fields.
refs: https://github.com/KumoCorp/kumomta/issues/405
Adjusts how we resolve the attachment name when processing mime
attachment parameters:
* First check Content-Disposition::filename
* Then check Content-Type::name
De-couple parsing out the `Content-Id` header from having
`Content-Disposition`.
In the lua bindings; remove the synthesized filename fallback;
we now just leave it nil to match the rust logic.