Compare commits

...

13 commits

Author SHA1 Message Date
James Kay
92a1729f36 Merge branch 'autoconfig' into 'master'
Add support for Mozilla-style autoconfig

See merge request simple-nixos-mailserver/nixos-mailserver!188
2024-12-24 01:26:24 +00:00
Antoine Eiche
63209b1def Release 24.11 2024-12-22 16:20:47 +00:00
lennart
26a56d0a8f Fix example for rejectSender
A domain prepended with an at sign does not work to reject senders on
domain level. Thus misleading documentation is fixed by removing it.
2024-12-20 00:15:57 +01:00
Sandro
c43d8c4a3c Fix wrong userAttrs default 2024-12-16 17:37:58 +00:00
Jeremy Fleischman
6db6c0dc72 Add instructions about creating a AAAA record 2024-12-16 17:35:11 +00:00
Jany Doe
e4aabd3de6 remove new line character if use agenix 2024-12-16 17:07:10 +00:00
Guillaume Girol
1cf6d01989 nix flake update 2024-11-24 00:16:56 +01:00
Guillaume Girol
0a801316cd tests: ignore debug message that looks like an error 2024-11-24 00:16:56 +01:00
Guillaume Girol
9919033068 tests: make the emails sent by mail-check.py look less like spam
rspamd complains that these emails miss these headers
2024-11-23 23:51:49 +01:00
Guillaume Girol
e901c56849 services.dnsmasq.extraConfig was removed on nixos-unstable 2024-11-23 23:51:49 +01:00
Guillaume Girol
3a082011dc recent nixos-unstable requires larger dh params 2024-11-23 12:00:00 +00:00
James ‘Twey’ Kay
1861e82add
address review comments 2023-09-11 22:13:58 +01:00
James ‘Twey’ Kay
14cc97446d
add a simple Mozilla-style autoconfig for nginx 2023-09-11 22:13:55 +01:00
15 changed files with 235 additions and 40 deletions

View file

@ -32,8 +32,8 @@ let
desc = prJobsets // {
"master" = mkFlakeJobset "master";
"nixos-23.11" = mkFlakeJobset "nixos-23.11";
"nixos-24.05" = mkFlakeJobset "nixos-24.05";
"nixos-24.11" = mkFlakeJobset "nixos-24.11";
};
log = {

View file

@ -8,14 +8,14 @@
For each NixOS release, we publish a branch. You then have to use the
SNM branch corresponding to your NixOS version.
* For NixOS 24.11
- Use the [SNM branch `nixos-24.11`](https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/tree/nixos-24.11)
- [Documentation](https://nixos-mailserver.readthedocs.io/en/nixos-24.11/)
- [Release notes](https://nixos-mailserver.readthedocs.io/en/nixos-24.11/release-notes.html#nixos-24-11)
* For NixOS 24.05
- Use the [SNM branch `nixos-24.05`](https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/tree/nixos-24.05)
- [Documentation](https://nixos-mailserver.readthedocs.io/en/nixos-24.05/)
- [Release notes](https://nixos-mailserver.readthedocs.io/en/nixos-24.05/release-notes.html#nixos-24-05)
* For NixOS 23.11
- Use the [SNM branch `nixos-23.11`](https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/tree/nixos-23.11)
- [Documentation](https://nixos-mailserver.readthedocs.io/en/nixos-23.11/)
- [Release notes](https://nixos-mailserver.readthedocs.io/en/nixos-23.11/release-notes.html#nixos-23-11)
* For NixOS unstable
- Use the [SNM branch `master`](https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/tree/master)
- [Documentation](https://nixos-mailserver.readthedocs.io/en/latest/)

View file

@ -278,7 +278,7 @@ in
dovecot = {
userAttrs = mkOption {
type = types.nullOr types.str;
default = "";
default = null;
description = ''
LDAP attributes to be retrieved during userdb lookups.
@ -506,7 +506,7 @@ in
rejectSender = mkOption {
type = types.listOf types.str;
example = [ "@example.com" "spammer@example.net" ];
example = [ "example.com" "spammer@example.net" ];
description = ''
Reject emails from these addresses from unauthorized senders.
Use if a spammer is using the same domain or the same sender over and over.
@ -1298,6 +1298,7 @@ in
imports = [
./mail-server/assertions.nix
./mail-server/autoconfig
./mail-server/borgbackup.nix
./mail-server/debug.nix
./mail-server/rsnapshot.nix

View file

@ -1,6 +1,11 @@
Release Notes
=============
NixOS 24.11
-----------
- No new feature, only bug fixes and documentation improvements
NixOS 24.05
-----------

View file

@ -20,25 +20,30 @@ an up and running mail server. Once the server is deployed, we could
then set all DNS entries required to send and receive mails on this
server.
Setup DNS A record for server
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Setup DNS A/AAAA records for server
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Add a DNS record to the domain ``example.com`` with the following
Add DNS records to the domain ``example.com`` with the following
entries
==================== ===== ==== =============
Name (Subdomain) TTL Type Value
==================== ===== ==== =============
``mail.example.com`` 10800 A ``1.2.3.4``
``mail.example.com`` 10800 AAAA ``2001::1``
==================== ===== ==== =============
If your server does not have an IPv6 address, you must skip the `AAAA` record.
You can check this with
::
$ ping mail.example.com
64 bytes from mail.example.com (1.2.3.4): icmp_seq=1 ttl=46 time=21.3 ms
...
$ nix-shell -p bind --command "host -t A mail.example.com"
mail.example.com has address 1.2.3.4
$ nix-shell -p bind --command "host -t AAAA mail.example.com"
mail.example.com has address 2001::1
Note that it can take a while until a DNS entry is propagated. This
DNS entry is required for the Let's Encrypt certificate generation
@ -58,9 +63,9 @@ common ones.
imports = [
(builtins.fetchTarball {
# Pick a release version you are interested in and set its hash, e.g.
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/nixos-23.05/nixos-mailserver-nixos-23.05.tar.gz";
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/nixos-24.11/nixos-mailserver-nixos-24.11.tar.gz";
# To get the sha256 of the nixos-mailserver tarball, we can use the nix-prefetch-url command:
# release="nixos-23.05"; nix-prefetch-url "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/${release}/nixos-mailserver-${release}.tar.gz" --unpack
# release="nixos-24.11"; nix-prefetch-url "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/${release}/nixos-mailserver-${release}.tar.gz" --unpack
sha256 = "0000000000000000000000000000000000000000000000000000";
})
];
@ -98,8 +103,11 @@ Set rDNS (reverse DNS) entry for server
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Wherever you have rented your server, you should be able to set reverse
DNS entries for the IPs you own. Add an entry resolving ``1.2.3.4``
to ``mail.example.com``.
DNS entries for the IPs you own:
- Add an entry resolving IPv4 address ``1.2.3.4`` to ``mail.example.com``.
- Add an entry resolving IPv6 ``2001::1`` to ``mail.example.com``. Again, this
must be skipped if your server does not have an IPv6 address.
.. warning::
@ -115,6 +123,9 @@ You can check this with
$ nix-shell -p bind --command "host 1.2.3.4"
4.3.2.1.in-addr.arpa domain name pointer mail.example.com.
$ nix-shell -p bind --command "host 2001::1"
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.2.ip6.arpa domain name pointer mail.example.com.
Note that it can take a while until a DNS entry is propagated.
Set a ``MX`` record

View file

@ -34,11 +34,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1717602782,
"narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=",
"lastModified": 1732014248,
"narHash": "sha256-y/MEyuJ5oBWrWAic/14LaIr/u5E0wRVzyYsouYY3W6w=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6",
"rev": "23e89b7da85c3640bbc2173fe04f4bd114342367",
"type": "github"
},
"original": {
@ -47,18 +47,18 @@
"type": "indirect"
}
},
"nixpkgs-24_05": {
"nixpkgs-24_11": {
"locked": {
"lastModified": 1717144377,
"narHash": "sha256-F/TKWETwB5RaR8owkPPi+SPJh83AQsm6KrQAlJ8v/uA=",
"lastModified": 1734083684,
"narHash": "sha256-5fNndbndxSx5d+C/D0p/VF32xDiJCJzyOqorOYW4JEo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "805a384895c696f802a9bf5bf4720f37385df547",
"rev": "314e12ba369ccdb9b352a4db26ff419f7c49fa84",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-24.05",
"ref": "nixos-24.11",
"type": "indirect"
}
},
@ -67,7 +67,7 @@
"blobs": "blobs",
"flake-compat": "flake-compat",
"nixpkgs": "nixpkgs",
"nixpkgs-24_05": "nixpkgs-24_05"
"nixpkgs-24_11": "nixpkgs-24_11"
}
}
},

View file

@ -7,14 +7,14 @@
flake = false;
};
nixpkgs.url = "flake:nixpkgs/nixos-unstable";
nixpkgs-24_05.url = "flake:nixpkgs/nixos-24.05";
nixpkgs-24_11.url = "flake:nixpkgs/nixos-24.11";
blobs = {
url = "gitlab:simple-nixos-mailserver/blobs";
flake = false;
};
};
outputs = { self, blobs, nixpkgs, nixpkgs-24_05, ... }: let
outputs = { self, blobs, nixpkgs, nixpkgs-24_11, ... }: let
lib = nixpkgs.lib;
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
@ -24,8 +24,8 @@
pkgs = nixpkgs.legacyPackages.${system};
}
{
name = "24.05";
pkgs = nixpkgs-24_05.legacyPackages.${system};
name = "24.11";
pkgs = nixpkgs-24_11.legacyPackages.${system};
}
];
testNames = [

View file

@ -0,0 +1,100 @@
{ config, lib, pkgs, ... }:
with lib;
let
ms = config.mailserver;
cfg = ms.autoconfig;
in
{
imports = [ ./webroot.nix ];
options.mailserver.autoconfig = mkOption {
description = ''
Generate a simple static Mozilla-style autoconfig.
See
https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration
for further information on the file format.
Note that for each domain in `domains`, this will generate a
nginx `virtualHost` for the `autoconfig` subdomain of that
domain.
In order for autoconfig to work, those domains must be
accessible (i.e. have DNS records).
'';
type = types.submodule {
options = {
enable = mkEnableOption "Mozilla-style autoconfig (requires nginx)";
emailProviderId = mkOption {
type = types.str;
example = "example.com";
default = ms.fqdn;
defaultText = "config.mailserver.fqdn";
description = ''
An ID for the email provider.
'';
};
domains = mkOption {
type = types.listOf types.str;
example = [ "example.com" "example.net" ];
default = ms.domains;
defaultText = "config.mailserver.domains";
description = ''
A list of domains for which to enable autoconfig.
'';
};
displayName = mkOption {
type = types.str;
example = "Joe's Email Provider";
default = cfg.emailProviderId;
defaultText = "config.mailserver.autoconfig.id";
description = ''
A user-readable name for the email provider.
'';
};
displayShortName = mkOption {
type = types.str;
example = "JoeMail";
default = cfg.displayName;
defaultText = "config.mailserver.autoconfig.displayName";
description = ''
A "short" user-readable name for the email provider.
'';
};
templateFile = mkOption {
type = types.path;
example = "/path/to/template.xml";
default = ./template.xml;
description = ''
A path to a template file to use.
'';
};
extraEmailProvider = mkOption {
type = types.lines;
default = "";
description = ''
Extra XML to be embedded at the end of the <emailProvider> element.
'';
};
webRoot = mkOption {
type = types.path;
visible = false;
};
};
};
};
config = mkIf config.mailserver.autoconfig.enable {
services.nginx.enable = true;
services.nginx.virtualHosts = mkMerge (map (domain: {
"autoconfig.${domain}".root = cfg.webRoot;
}) cfg.domains);
};
}

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<clientConfig version="1.1">
<emailProvider id="@emailProviderId@">
@domains@
<displayName>@displayName@</displayName>
<displayShortName>@displayShortName</displayShortName>
@imapSslServer@
@imapServer@
@pop3SslServer@
@pop3Server@
<outgoingServer type="smtp">
<hostname>@fqdn@</hostname>
<port>587</port>
<socketType>STARTTLS</socketType>
<authentication>password-cleartext</authentication>
<username>%EMAILADDRESS%</username>
</outgoingServer>
<outgoingServer type="smtp">
<hostname>@fqdn@</hostname>
<port>25</port>
<socketType>STARTTLS</socketType>
<authentication>password-cleartext</authentication>
<username>%EMAILADDRESS%</username>
</outgoingServer>
@extraEmailProvider@
</emailProvider>
</clientConfig>

View file

@ -0,0 +1,49 @@
{ config, lib, pkgs, ... }:
with lib;
let
ms = config.mailserver;
cfg = ms.autoconfig;
# none of the available parameters are configurable in
# simple-mailserver so these templates aren't configurable either
incomingServer = enable: port: socketType: optionalString enable ''
<incomingServer type="imap">
<hostname>${ms.fqdn}</hostname>
<port>${builtins.toString port}</port>
<socketType>${socketType}</socketType>
<authentication>password-cleartext</authentication>
<username>%EMAILADDRESS%</username>
</incomingServer>
'';
# we currently only support STARTTLS for outgoing servers
outgoingServer = port: ''
<outgoingServer type="smtp">
<hostname>${ms.fqdn}</hostname>
<port>${builtins.toString port}</port>
<socketType>STARTTLS</socketType>
<authentication>password-cleartext</authentication>
<username>%EMAILADDRESS%</username>
</outgoingServer>
'';
in {
mailserver.autoconfig.webRoot = pkgs.substituteAll ({
name = "config-v1.1.xml";
dir = "mail";
src = cfg.templateFile;
} // {
hostname = ms.fqdn;
inherit (cfg)
emailProviderId displayName displayShortName extraEmailProvider;
imapSslServer = incomingServer ms.enableImapSsl 993 "SSL";
imapServer = incomingServer ms.enableImapSsl 143 "STARTTLS";
pop3SslServer = incomingServer ms.enablePop3Ssl 995 "SSL";
pop3Server = incomingServer ms.enablePop3 110 "STARTTLS";
smtpServer = outgoingServer 25;
submissionServer = outgoingServer 587;
domains = concatMapStringsSep
"\n "
(x: "<domain>${x}</domain>")
cfg.domains;
});
}

View file

@ -62,7 +62,7 @@ in
cat ${file} > ${destination}
echo -n '${prefix}' >> ${destination}
cat ${passwordFile} >> ${destination}
cat ${passwordFile} | tr -d '\n' >> ${destination}
echo -n '${suffix}' >> ${destination}
chmod 600 ${destination}
'';

View file

@ -5,6 +5,7 @@ import uuid
import imaplib
from datetime import datetime, timedelta
import email
import email.utils
import time
RETRY = 100
@ -15,11 +16,16 @@ def _send_mail(smtp_host, smtp_port, smtp_username, from_addr, from_pwd, to_addr
"From: {from_addr}",
"To: {to_addr}",
"Subject: {subject}",
"Message-ID: {random}@mail-check.py",
"Date: {date}",
"",
"This validates our mail server can send to Gmail :/"]).format(
from_addr=from_addr,
to_addr=to_addr,
subject=subject)
subject=subject,
random=str(uuid.uuid4()),
date=email.utils.formatdate(),
)
retry = RETRY

View file

@ -505,7 +505,7 @@ pkgs.nixosTest {
with subtest("no warnings or errors"):
server.fail("journalctl -u postfix | grep -i error >&2")
server.fail("journalctl -u postfix | grep -i warning >&2")
server.fail("journalctl -u dovecot2 | grep -i error >&2")
server.fail("journalctl -u dovecot2 | grep -v 'imap-login: Debug: SSL error: Connection closed' | grep -i error >&2")
# harmless ? https://dovecot.org/pipermail/dovecot/2020-August/119575.html
server.fail(
"journalctl -u dovecot2 |grep -v 'Expunged message reappeared, giving a new UID'| grep -v 'FTS Xapian: Box is empty' | grep -i warning >&2"

View file

@ -1,3 +1,3 @@
{
security.dhparams.defaultBitSize = 1024; # minimum size required by dovecot
security.dhparams.defaultBitSize = 2048; # minimum size required by dovecot
}

View file

@ -30,12 +30,7 @@ let
};
services.dnsmasq = {
enable = true;
# Fixme: once nixos-22.11 has been removed, could be replaced by
# settings.mx-host = [ "domain1.com,domain1,10" "domain2.com,domain2,10" ];
extraConfig = ''
mx-host=domain1.com,domain1,10
mx-host=domain2.com,domain2,10
'';
settings.mx-host = [ "domain1.com,domain1,10" "domain2.com,domain2,10" ];
};
};