999 Commits

Author SHA1 Message Date
Mechiel Lukkien
833a67fe3d add config option to disable tls client auth during tls handshakes
to work around clients, like the gmail smtp client, that tries to
authenticate with a webpki-issued certificate (which we don't know).

i tried specifying a list of accepted (subjects of) CA certs during the
tls handshake (with just 1 entry, with "xmox.nl" as common name), which
clients can use to influence their cert selection.  however, the gmail
smtp client ignores it, so not a solution for the issue where this was
raised. also, specifying a list of accepted certs could cause other
clients to not send their client cert anymore, breaking existing setups.

i also considered only asking for tls client auth when at least one
account has a tls pubkey configured. but decided against it since any
account can add one on their own (without system admin interaction),
changing behaviour of the system and potentially breaking existing
submission/tls configs.

we now also print the "subject" and "issuer" of certs when tls client
auth fails, should be useful for future debugging.

for issue #359
2025-06-09 12:33:10 +02:00
Mechiel Lukkien
f5b8c64b84 fix typo's 2025-06-09 10:00:53 +02:00
Mechiel Lukkien
f1259ee80e add config option to disable rate limiting for the webserver, and take a reverse proxy into account when finding the ip to use for webserver ratelimting
another approach i looked at was enabling/disabling rate limiting per
web handler. but we want to apply the rate limit as early as possible
(not after we've already done quite some work for the request), and with
per-handler rate limits on/off the code would be sprinkled with calls to
rate limiting. this is probably good enough for now. other protocols are
less likely to need this.

we were always using the ip address of the connection for rate limiting.
but some setups have a reverse proxy in front. if any handler on a
http/https port is marked as "forwarded" (with a reverse proxy), we use
the ip address from the x-forwarded-for header (like we already did for
authentication requests over http).

for issue #346
2025-05-15 20:16:49 +02:00
Mechiel Lukkien
bb438488c5 add "Fail" transport, that immediately fails delivery
allows configs that prevent outgoing deliveries (globally, per domain,
or per account) from/to certain domains.

for issue #347
2025-05-15 17:59:49 +02:00
Mechiel Lukkien
91bfff220e add mx preference to smtpclient.GatherDestinations
mostly so moxtools can show the mx preferences in its output
2025-05-15 16:37:53 +02:00
Mechiel Lukkien
cc627af263 fix tests for previous commit
the build for go1.23 generated a different doc.go...
2025-05-15 14:42:07 +02:00
Mechiel Lukkien
76e58f4a63 fix building previous commit with go1.23 2025-05-15 14:25:18 +02:00
Mechiel Lukkien
4a14abc254 add "mox smtp dial" subcommand, for debugging connectivity issues
with various options for the tls connection.
2025-05-15 14:12:08 +02:00
Mechiel Lukkien
70bbfc8f10 fix findings from gopls 2025-05-13 09:33:37 +02:00
Mechiel Lukkien
aff279711c add ":z" to docker-compose volumes and remove deprecated version field from yml files
the ":z" is required on selinux systems, like fedora. and doesn't seem
to hurt on other systems.
2025-05-12 10:29:22 +02:00
Alice
2e0eea88b0
fix typos in referrer header
It should be referer in both cases, which whilst misspelled is the actual header name
2025-04-25 19:16:32 +01:00
Mechiel Lukkien
baacdbca18
when registering login attempts, use X-Forwarded-For header for finding the IP address
Which we already did for the rate limiting.

Hopefully solves issue #338.
2025-04-22 09:05:34 +02:00
Mechiel Lukkien
ee99e82cf4
add v0.0.15 to website and rotate apidiff v0.0.15 2025-04-18 21:25:37 +02:00
Mechiel Lukkien
b7262d536d
nit, tweaking release process order 2025-04-18 20:53:28 +02:00
Mechiel Lukkien
794ef75d17
accept incoming DMARC and TLS reports with reporting addresses containing catchall separator(s)
Such as "-" when addresses are dmarc-reports@ and tls-reports@.

Existing configuration files can have these combinations. We don't allow them
to be created through the webadmin interface, as this is a likely source of
confusion about how addresses will be matched. We already didn't allow regular
addresses containing catchall separators.
2025-04-18 12:36:01 +02:00
Mechiel Lukkien
4eddf5885d
change default dmarc & tls reporting address so they don't contain a dash
The defaults for a new domain were dmarc-reports@ and tls-reports@. But some
setups use "-" as catchall separator, which currently would cause messages to
those addresses to be rejected with a "no such user" smtp error.

Better to prevent these issues in the future by using dmarcreports@ and
tlsreports@ localparts.

The config checks don't enforce that the DMARC and TLS reporting addresses
don't contain the localpart catchall separator. A next commit will fix
accepting incoming reports to such addresses.
2025-04-18 11:39:45 +02:00
Mechiel Lukkien
53f391ad18
fix flaky test where closing the imapclient connection fails because the server has also closed the tls connection 2025-04-18 09:23:30 +02:00
Mechiel Lukkien
14af5bbb12
when reparsing all messages, actually store the new mime structure in the database 2025-04-18 09:05:09 +02:00
Mechiel Lukkien
75bb1bfa2f
queue: before removing files from the queue, close them, so removing doesn't fail on windows
Mostly relevant for localserve, since full operation doesn't work on windows.
2025-04-17 21:08:07 +02:00
Mechiel Lukkien
5f9f45983d
use smaller batch size when reparsing all messages, to stay response when making changes on slower machines 2025-04-17 09:47:53 +02:00
Mechiel Lukkien
0ce0296a9f
update public suffix list 2025-04-16 20:09:11 +02:00
Mechiel Lukkien
805ae0d827
update to latest golang.org/x dependencies 2025-04-16 20:06:58 +02:00
Mechiel Lukkien
1b2b152cb5
add "mox config account list", printing all accounts and whether they are disabled
based on question from wisse on slack
2025-04-16 20:06:58 +02:00
Mechiel Lukkien
31c22618f5
automatically reparse all messages, in the background, after addition of header fields in the parsed mime form of messages in the message index database
With that recent change, we would keep track of Content-* headers of parsed
messages. We could ask admins to run a command to reparse messages for all
accounts. But instead we just do it automatically when opening the account. We
keep track whether we did the upgrade. And we do it in the background. Those
recent changes were to add optional fields to the IMAP fetch "bodystructure"
responses. There is a small chance that an IMAP client requests these fields
before they are properly populated with the reparse (only existing messages,
new incoming messages are parsed with the new code). We could try to detect
whether the upgrade has completed, and chance IMAP behaviour based on that. But
the complexity and long-term maintenance burden doesn't seem worth it. Worst
case, we'll temporarily claim some relatively unimportant headers aren't
present on a message. Most email clients won't even look at those fields, but
will parse them message themselves instead.
2025-04-16 20:06:58 +02:00
Mechiel Lukkien
07533252b3
message: when parsing a message, don't treat absent header and empty header value the same
We now use "*string" for such header fields, for Content-* fields, as used in
the imapserver when responding to FETCH commands. We'll now return NIL for an
absent header, and "" (empty string) if the header value is empty.
2025-04-16 20:06:45 +02:00
Mechiel Lukkien
3fe765dce9
imapserver: fix fuzz tests
The acc.Close() at the end of the fuzzing would find inconsistencies. For
example, message files on disk that aren't in the database file. I don't
understand what is happening there, the database file on disk does have those
messages, and it seems the database file is getting replaced. When running the
same code not as a fuzzing test but as a regular Go test doesn't show the
problem. So it seems to be some interaction with fuzzing. The problem is
"solved" (feels more like side-stepped), by starting each fuzz test with a
clean database. We still open & close the account in each fuzz test, and it
doesn't find consistency problems.
2025-04-16 11:21:01 +02:00
Mechiel Lukkien
e7b562e3f2
imapclient: first step towards making package usable as imap client with other imap servers, and minor imapserver bug fix
The imapclient needs more changes, like more strict parsing, before it can be a
generally usable IMAP client, these are a few steps towards that.

- Fix a bug in the imapserver METADATA responses for TOOMANY and MAXSIZE.
- Split low-level IMAP protocol handling (new Proto type) from the higher-level
  client command handling (existing Conn type). The idea is that some simple
  uses of IMAP can get by with just using these commands, while more intricate
  uses of IMAP (like a synchronizing client that needs to talk to all kinds of
  servers with different behaviours and implemented extensions) can write custom
  commands and read untagged responses or command completion results
  explicitly. The lower-level method names have clearer names now, like
  ReadResponse instead of Response.
- Merge the untagged responses and (command completion) "Result" into a new
  type Response. Makes function signatures simpler. And make Response implement
  the error interface, and change command methods to return the Response as error
  if the result is NO or BAD. Simplifies error handling, and still provides the
  option to continue after a NO or BAD.
- Add UIDSearch/MSNSearch commands, with a custom "search program", so mostly
  to indicate these commands exist.
- More complete coverage of types for response codes, for easier handling.
- Automatically handle any ENABLED or CAPABILITY untagged response or response
  code for IMAP command methods on type Conn.
- Make difference between MSN vs UID versions of
  FETCH/STORE/SEARCH/COPY/MOVE/REPLACE commands more clear. The original MSN
  commands now have MSN prefixed to their name, so they are grouped together in
  the documentation.
- Document which capabilities are needed for a command.
2025-04-15 08:37:18 +02:00
Mechiel Lukkien
2c1283f032
imapclient: clean up function signature of New, allowing for future options too 2025-04-11 21:04:13 +02:00
Mechiel Lukkien
af3e9351bc
imapserver: simplify and fix logic around processing changes while opening a mailbox (with SELECT or EXAMINE)
We were first getting UIDs in a transaction with a lock. Then getting the
changes and processing them in a special way. And then processing for qresync
in a new transaction. The special processing of changes is now gone, it seems
to have skipped adding/removing uids to the session, which can't be correct.
The new approach is just using a lock and transaction and process the whole
opening of the mailbox, and not processing any changes as part of the open, and
getting rid of the special "initial" mode processing a mailbox.
2025-04-11 20:28:35 +02:00
Mechiel Lukkien
fd5167fdb3
imapserver: enable test that checked that an expunged message can still be read in sessions when they haven't processed the deletion yet.
We've been keeping track of references before we erase the message file for a
while now.
2025-04-11 18:27:42 +02:00
Mechiel Lukkien
1a6d268e1d
imapserver: check for UIDNEXT overflow when adding a message to a mailbox
Return an error, with instructions so a user may be able to work around the
issue.
2025-04-11 18:22:29 +02:00
Mechiel Lukkien
507ca73b96
imapserver: implement UIDONLY extension, RFC 9586
Once clients enable this extension, commands can no longer refer to "message
sequence numbers" (MSNs), but can only refer to messages with UIDs. This means
both sides no longer have to carefully keep their sequence numbers in sync
(error-prone), and don't have to keep track of a mapping of sequence numbers to
UIDs (saves resources).

With UIDONLY enabled, all FETCH responses are replaced with UIDFETCH response.
2025-04-11 11:45:49 +02:00
Mechiel Lukkien
8bab38eac4
imapserver: implement NOTIFY extension from RFC 5465
NOTIFY is like IDLE, but where IDLE watches just the selected mailbox, NOTIFY
can watch all mailboxes. With NOTIFY, a client can also ask a server to
immediately return configurable fetch attributes for new messages, e.g. a
message preview, certain header fields, or simply the entire message.

Mild testing with evolution and fairemail.
2025-04-11 10:06:34 +02:00
Mechiel Lukkien
5a7d5fce98
run ineffassign (fast) before staticcheck (slow) 2025-04-07 18:40:54 +02:00
Mechiel Lukkien
902de0e1f9
queue: in log lines about delivery, we had both "attempts" starting at 0 and "attempt" starting at 1, keep only "attempts" starting at 1
from eric l, thanks!
2025-04-07 13:35:42 +02:00
Mechiel Lukkien
39c21f80cd
imapserver: return proper response for FETCH of "BODY[1.MIME]" where 1 is a message
MIME returns the part headers. If 1 is a message, i.e. a message/rfc822 or
message/global, for example when top-level is a multipart/mixed, we were
returning the MIME headers from the message, not from the part.

We also shouldn't be returning a MIME-Version header or the separating newline
for MIME. Those are for MIME headers of a message, but the "MIME" fetch body
part is always about the part.

Found after looking into FETCH BODY handling for issue #327.
2025-04-07 12:15:13 +02:00
Mechiel Lukkien
462568d878
webmail: for "cid"/content-id's used in html, look for them in all other parts, not just when there is a multipart/related in the message
The gmail apps generate messages consisting of multipart/mixed, with text/html
referring to a sibling image/jpeg. We weren't resolving that cid before.

Related to issue #327.
2025-04-07 11:10:14 +02:00
Mechiel Lukkien
2defbce0bc
imapserver: return all the extensible fields for bodystructure, notably for content-disposition
The gmail iOS/Android app were showing mime image parts as (garbled) text
instead of rendering them as image. By returning all the optional fields in the
bodystructure fetch attribute, the gmail app renders the image as expected by
the user. So we now add all fields. We didn't before, because we weren't
keeping track of Content-MD5, Content-Language and Content-Location header
fields, since they aren't that useful.

Messages in mailboxes have to be reparsed:
	./mox reparse

Without reparsing, imap responses will claim the extra fields
(content-disposition) are absent for existing messages, instead of not claiming
anything at all, which is what we did before.

Accounts and all/some mailboxes can get their "uid validity" bumped ("./mox
bumpuidvalidity $account [$mailbox]"), which should trigger clients to load all
messages from scratch, but gmail doesn't appear to notice, so it would be
better to remove & add the account in gmail.

For issue #327, also relevant to issue #217.
2025-04-05 15:46:17 +02:00
Mechiel Lukkien
69d2699961
write base64 message parts with 76 data bytes on a line instead of 78
As required by RFC 2045 (MIME). The 78 byte lines work in practice, except that
SpamAssassin has rules that give messages with 78-byte lines spam points.

Mentioned by kjetilho on irc.
2025-04-03 10:22:15 +02:00
Mechiel Lukkien
00c8db98e6
start more function names/calls with x when they handle errors through panics
mostly the imapserver and smtpserver connection write and read methods.
2025-04-02 13:59:46 +02:00
Mechiel Lukkien
deb57462a4
update list of sponsors, add logo's and link to the nlnet projects 2025-04-02 11:24:59 +02:00
Mechiel Lukkien
479bf29124
imapserver: implement the MULTISEARCH extension, with its ESEARCH command 2025-03-31 18:34:23 +02:00
Mechiel Lukkien
5dcf674761
webmail: reconnect automatically in more cases
Before, we would only reconnect the SSE connection when the previous one lasted
10 minutes.  For some reason, firefox disconnects SSE connections when there is
any network change. Running the docker integration tests changes the network a
few time in quick succession, prevent further automatic reconnects.

This changes the "stop reconnection automatically" period from 10 minutes to 5
seconds.
2025-03-30 14:54:29 +02:00
Mechiel Lukkien
aba0061073
small tweak to docs and website, mentioning EIA in the context of internalized email 2025-03-30 11:03:06 +02:00
Mechiel Lukkien
cc5e3165ea
imapserver: implement "inprogress" response code (RFC 9585) for keepalive during long search
For long searches in big mailboxes, without any matches, we would previously
keep working and not say anything. Clients could interpret this silence as a
broken connection at some point. We now send a "we're still searching" untagged
OK responses with code INPROGRESS every 10 seconds while we're still searching,
to prevent the client from closing the connection. We also send how many
messages we've processed, and usually also how many we need to process in grand
total. Clients can use this to show a progress bar.
2025-03-30 10:43:02 +02:00
Mechiel Lukkien
3e128d744e
for the web interfaces, ensure the effective configured http paths end in a slash to prevent 404's and/or errors accessing the web interfaces
The default paths for the web interfaces, such as /admin/, /account/, /webmail/
and /webapi/ end with a slash. They should end with a slash because we use the
path when restricting cookies to just that web interface. You could configure
paths not ending with a slash, but due to using http.StripPrefix, and our
handler, some of those requests may not work properly.

We now warn if configured paths don't end with a trailing slash when parsing
the config file. We normally error out when such things happen, but users
probably have paths without trailing slashes configured, and we don't want to
break them on a future upgrade. We now use an effective path that includes the
trailing slash.

We would always redirect requests to the configured paths but without trailing
slash to the path with trailing slash, and that stays.

For issue #325 by odama626.
2025-03-29 22:00:55 +01:00
Mechiel Lukkien
3a3a11560e
web interfaces: don't include version number in html, only return it after authentication
second round for issue #322
2025-03-29 20:46:53 +01:00
Mechiel Lukkien
eeeabdc6de
fix build with previous commit that didn't sync frontend
not at my sharpest...
2025-03-29 20:16:05 +01:00
Mechiel Lukkien
3ac38aacca
imapserver: fix storing previews when requested over imap and they are missing from the database
found while testing.
2025-03-29 20:13:10 +01:00
Mechiel Lukkien
6ab31c15b7
imapserver: actually announce PREVIEW extension 2025-03-29 18:28:33 +01:00