Commit Graph

64 Commits

Author SHA1 Message Date
l cf76dfd358 test: place #[tokio::test] after rstest case macros (#192)
Otherwise only the first case is built.
2026-08-18 12:21:29 +02:00
Jagoda Estera Ślązak f064b9ec2c feat(logs): Log incoming mailer-daemon message sources (#191)
Logs mailer-daemon messages separately from other unencrypted mails.

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:29 +02:00
Jagoda Estera Ślązak 230415914b feat(transport): Worker eviction (#185)
Adds max worker capacity of 500 to the worker pool,
and an automatic shutdown of idle workers.
Messages that would cause the capacity to be exceeded,
are deferred.

Additionally, ensures that the same worker
is not spawned by two tasks at the same time.

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:29 +02:00
Jagoda Ślązak acc00badd4 refactor: Implement Display for AddressDomain
Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:29 +02:00
Jagoda Ślązak 5d37a73795 test: Test filtermail-transport
Adds filtermail-transport tests and
a test setup for recording SMTP transactions.

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:29 +02:00
Jagoda Ślązak cfc6eb9b21 feat(transport): Destination worker pool
Implements a per-destination worker pool,
so that connections to the same destination
are not parallelized, but instead queued.
If a queue is full, new messages are immediately
deferred, before mail data is sent from postfix.

Closes: #141

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:29 +02:00
Jagoda Estera Ślązak 0177502929 feat: switch to aws-lc-rs cryptography provider (#178)
Switches crypto provider to keep
chatmail codebase consistent,
analogous to https://github.com/chatmail/core/pull/8313

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:29 +02:00
l 8cc578a5bb fix: ignore CNAME records when resolving TXT records (#177) 2026-08-18 12:21:29 +02:00
Andrey 0xdc09 0c0e84f649 fix(resolver): disable negative caching (#170) 2026-08-18 12:21:29 +02:00
Jagoda Estera Ślązak b75717c205 fix(smtp-server): Correct error when EOF while reading DATA (#168)
Log
`Unexpected EoF while receiving DATA!`
instead of
`Malformed DATA line without CRLF ending!`

Fixes: #165

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:29 +02:00
l d12e1d53f7 fix: switch ratelimiter to MonotonicClock (#167)
There is a known bug that `quanta` clock
used by default sometimes jumps back:
<https://github.com/metrics-rs/quanta/issues/111>.
This results in `governor` rate limiter
incorrectly rejecting the messages
even when less than the configured burst size
has been sent.

Switched to standard monotonic clock
which does not have this problem.
I tested that this fixed the problem for me,
chatmail relay test `test_exceed_rate_limit`
stopped failing randomly.

Fixes <https://github.com/chatmail/filtermail/issues/166>
2026-08-18 12:21:28 +02:00
link2xt 4d6f6af20b fix: do not crash if accepting new connection fails
If we run out of file descriptors, we cannot do anything
to accept queued connections, so at least don't crash the process.
Fixes <https://github.com/chatmail/filtermail/issues/139>.
2026-08-18 12:21:28 +02:00
holger krekel 7d7bccd44b feat!: remove passthrough options that allowed unencrypted mail to pass
see https://github.com/chatmail/relay/pull/970/ for the related removal of chatmail.ini options
2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak 54ecc59345 feat: Improved SMTP error responses (#147)
Fixes: #140

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
holger krekel 02e68ac146 fix: return HTTP 200 because madmail expects it, and make sure https is immediately retried when SMTP fails (#153) 2026-08-18 12:21:28 +02:00
l 49b65b676a fix: Validate mail data (#150)
Do not allow bare CR and LF etc.
2026-08-18 12:21:28 +02:00
holger krekel 0473f5a588 fix: advertise 8BITMIME to prevent conversion after DKIM signing (#149)
for bounces postfix sets Content-Transfer-Encoding: 8bit
which causes a quoted-printable conversion when filtermail SMTP does not offer 8BITMIME,
which in turn breaks DKIM verification.
2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak d07a51522d perf(smtp-client): Use pipelining if server advertises support (#146)
Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak 0c917d4d87 fix(smtp-client): Handle 421 on reused connection (#145)
If a reused connection was closed
in the meantime, open a new connection,
instead of failing immediately.

Fixes #143

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak 2e80eb651f chore(deps): Upgrade hickory-resolver (#138) 2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak 2ddd5d0cc7 feat: https transport channel (#122)
Transport mode:
Implements an additional mail delivery
channel over HTTPS.

Incoming mode:
Adds a http server listening for
incoming messages delivered over HTTPS.

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
Jagoda Ślązak 3c32af1c47 refactor(transport): Explicitly handle RFC7505 null MX
Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
Jagoda Ślązak 4131fd0823 fix: Implement missing "implicit MX" rule
Implements "implicit MX" as described by
https://datatracker.ietf.org/doc/html/rfc5321#section-5.1

Fixes: #126
Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak 82a2a8e39f feat(smtp-server): Log malformed SMTP commands (#118)
Closes #110

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak 25c8987904 perf(smtp-client): Cache connections (#117) 2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak 21b4c0d1a8 feat(transport): Remote delivery over SMTP (#104)
Implements a new mode "transport",
that allows filtermail to be used for
remote delivery.

In transport mode, filtermail listens for LMTP
connections, splits messages by domain
and performs delivery to remote MTAs over SMTP.

SMTP client tries to open socket on all resolved
addresses in parallel and uses one that succeeds
the first, fixing the issue described in:
chatmail/relay#900

Extends the built-in SMTP client
with STARTTLS support.

Extends the built-in SMTP server
with LMTP greeting support.

Groundwork required for mxdeliv endpoint
(HTTP channel for MTA-to-MTA communication):
chatmail/relay#900

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak 1518537ae4 feat: Log disabled recipients (#113)
Logs disabled recipient addresses
when removing them from RCPT TO.

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak 7f1521d7cd feat: Add experimental option to disable mailboxes (#108)
Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak af581d558f feat(resolver): Enable DNSSEC (#94)
From hickory-resolver docs:
> To enable DNSSEC, enable the dnssec-ring feature.

Related: https://github.com/chatmail/relay/issues/877
Related: https://github.com/hickory-dns/hickory-dns/issues/3519
Closes: https://github.com/chatmail/filtermail/issues/93

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
Andrey 0xdc09 d4acf064a9 refactor: derive Default for Envelope (#100) 2026-08-18 12:21:28 +02:00
Andrey 0xdc09 85395860bc feat: configurable hosts for listen and reinject (#84)
Adds configurable listen IP and postfix host 
via `filtermail_host` and `postfix_host` chatmail.ini config fields.
2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak e9fdbf39d4 feat!: Remove IP verification for domain-literals (#90)
BREAKING CHANGE: messages using domain-literal
  addresses don't require to match the origin
  SMTP connection IP anymore.

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
Andrey 0xdc09 199434e602 refactor: use enum for mode cli arg (#83) 2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak 93c0c3a891 feat: Check incoming email return address (#72)
If the MAIL FROM doesn't match the From header,
we do not reject the mail, as this can be caused
by e.g. SRS forwarding. Instead, we reset the envelope
address, so it is reinjected as `MAIL FROM:<>`
to prevent sending a bounce message.

Closes #67

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak b05164a86e refactor: Check if email is encrypted before verifying DKIM (#71)
This way we won't be logging DKIM rejections on messages that
would be rejected anyway due to not being encrypted.

Fixes #69

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:28 +02:00
Jagoda Estera Ślązak d64d546582 fix(logs): Log correct address for outbound messages (#70)
Fixes #68

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:27 +02:00
Jagoda Estera Ślązak 4e274ae280 fix(logs): Log From address instead of envelope MAIL FROM. (#66)
Fixes #64

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:27 +02:00
Jagoda Estera Ślązak 8fefc1cc94 fix(dkim): Accept TXT records with escaped quotes (#61) 2026-08-18 12:21:27 +02:00
Jagoda Estera Ślązak 83aa54bb82 fix(smtp): Properly handle bounce messages (#63)
Closes #58

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:27 +02:00
Jagoda Estera Ślązak 9d22b2b79a fix(dkim): Accept TXT records with no v= tag (#62)
Cache at most 3 TXT records instead of trying to find one that includes `DKIM`.

Closes #59

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:27 +02:00
Jagoda Estera Ślązak d823b28390 feat: Save rejected messages to /tmp (#55) 2026-08-18 12:21:27 +02:00
l 4fde0d5c5f refactor: do not copy the mail in memory for DKIM verification (#54)
`String::from_utf8_lossy` always copies the data
for the case when it needs to replace invalid UTF-8,
but we don't want invalid UTF-8 anyway as replacing
invalid UTF-8 characters will break DKIM signature.
2026-08-18 12:21:27 +02:00
Jagoda Estera Ślązak 5b24879573 fix(dkim): Make simple header canonicalization work properly (#53)
Previously header parsing caused leading whitespaces to be
trimmed in HeaderBody, which resulted in incorrect simple
header canonicalization.

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:27 +02:00
Jagoda Estera Ślązak 223fa3c67b chore(tests): Add a way to disable DKIM for tests (#50)
Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:27 +02:00
Jagoda Estera Ślązak 3dfac56db9 feat: Support addresses using domain literals (#42)
If the incoming email comes from address that uses
domain literals `[<ipv4>]` or `[IPv6:<ipv6>]`,
skip DKIM verification and instead check IP
alignment with originating IP from XFORWARD
command.

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:27 +02:00
Jagoda Estera Ślązak 23074f0898 feat!: DKIM verifier (#35)
* feat!: DKIM verifier

This implements a DKIM verification as well as a strict
DKIM signature alignment check with domain in `From`
header address.

Caches the retrieved RDATA using in-memory LRU.

BREAKING CHANGE: incoming messages now require DKIM signatures
  aligned to domain of the `From` header address.

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>

* chore(license): License binaries under GPLv3

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>

---------

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:27 +02:00
Jagoda Estera Ślązak 5c603db830 feat: Support legacy, pre-OpenPGP packet format (#44)
Support legacy packet format for compatibility with GnuPG.

Closes: #43

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:27 +02:00
Jagoda Estera Ślązak f34642e96c refactor: Use a custom, minimal SMTP client instead of lettre (#33)
This disables the Nagle's algorithm on re-insertion.

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:27 +02:00
Jagoda Estera Ślązak 0dfc3fae4e refactor: Remove unnecessary Arc (#36)
`Arc` around handler configs are not needed,
as they are not shared.

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:27 +02:00
Jagoda Estera Ślązak f2941c9807 feat: Configurable rate limiter max burst size (#28)
Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-08-18 12:21:27 +02:00