2019-02-05 07:03:04 +01:00
|
|
|
{ config, lib, pkgs, ... }:
|
2018-06-26 23:41:30 +02:00
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
let
|
|
|
|
|
|
|
|
cfg = config.accounts.email;
|
|
|
|
|
2018-09-08 11:45:29 +02:00
|
|
|
gpgModule = types.submodule {
|
|
|
|
options = {
|
|
|
|
key = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
|
|
|
The key to use as listed in <command>gpg --list-keys</command>.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
signByDefault = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = "Sign messages by default.";
|
|
|
|
};
|
|
|
|
|
|
|
|
encryptByDefault = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = "Encrypt outgoing messages by default.";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
signatureModule = types.submodule {
|
|
|
|
options = {
|
|
|
|
text = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "";
|
|
|
|
example = ''
|
|
|
|
--
|
|
|
|
Luke Skywalker
|
|
|
|
May the force be with you.
|
|
|
|
'';
|
|
|
|
description = ''
|
|
|
|
Signature content.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2022-04-29 22:01:53 +02:00
|
|
|
command = mkOption {
|
|
|
|
type = with types; nullOr path;
|
|
|
|
default = null;
|
|
|
|
example = literalExpression ''
|
|
|
|
pkgs.writeScript "signature" "echo This is my signature"
|
|
|
|
'';
|
|
|
|
description = "A command that generates a signature.";
|
|
|
|
};
|
|
|
|
|
2018-09-08 11:45:29 +02:00
|
|
|
showSignature = mkOption {
|
|
|
|
type = types.enum [ "append" "attach" "none" ];
|
|
|
|
default = "none";
|
|
|
|
description = "Method to communicate the signature.";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2018-06-26 23:41:30 +02:00
|
|
|
tlsModule = types.submodule {
|
|
|
|
options = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
description = ''
|
|
|
|
Whether to enable TLS/SSL.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
useStartTls = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = ''
|
|
|
|
Whether to use STARTTLS.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
certificatesFile = mkOption {
|
2021-08-02 20:23:50 +02:00
|
|
|
type = types.nullOr types.path;
|
2018-08-16 23:09:20 +02:00
|
|
|
default = config.accounts.email.certificatesFile;
|
|
|
|
defaultText = "config.accounts.email.certificatesFile";
|
2018-06-26 23:41:30 +02:00
|
|
|
description = ''
|
|
|
|
Path to file containing certificate authorities that should
|
|
|
|
be used to validate the connection authenticity. If
|
|
|
|
<literal>null</literal> then the system default is used.
|
|
|
|
Note, if set then the system default may still be accepted.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
imapModule = types.submodule {
|
|
|
|
options = {
|
|
|
|
host = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
example = "imap.example.org";
|
|
|
|
description = ''
|
|
|
|
Hostname of IMAP server.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
port = mkOption {
|
2019-08-19 20:37:48 +02:00
|
|
|
type = types.nullOr types.port;
|
2018-06-26 23:41:30 +02:00
|
|
|
default = null;
|
|
|
|
example = 993;
|
|
|
|
description = ''
|
|
|
|
The port on which the IMAP server listens. If
|
|
|
|
<literal>null</literal> then the default port is used.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
tls = mkOption {
|
|
|
|
type = tlsModule;
|
2020-04-06 12:51:11 +02:00
|
|
|
default = { };
|
2018-06-26 23:41:30 +02:00
|
|
|
description = ''
|
|
|
|
Configuration for secure connections.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-06-22 00:11:53 +02:00
|
|
|
jmapModule = types.submodule {
|
|
|
|
options = {
|
|
|
|
host = mkOption {
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = null;
|
|
|
|
example = "jmap.example.org";
|
|
|
|
description = ''
|
|
|
|
Hostname of JMAP server.
|
|
|
|
</para><para>
|
|
|
|
If both this option and <xref
|
|
|
|
linkend="opt-accounts.email.accounts._name_.jmap.sessionUrl"/> are specified,
|
|
|
|
<code>host</code> is preferred by applications when establishing a
|
|
|
|
session.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
sessionUrl = mkOption {
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = null;
|
|
|
|
example = "https://jmap.example.org:443/.well-known/jmap";
|
|
|
|
description = ''
|
|
|
|
URL for the JMAP Session resource.
|
|
|
|
</para><para>
|
|
|
|
If both this option and <xref
|
|
|
|
linkend="opt-accounts.email.accounts._name_.jmap.host"/> are specified,
|
|
|
|
<code>host</code> is preferred by applications when establishing a
|
|
|
|
session.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2018-06-26 23:41:30 +02:00
|
|
|
smtpModule = types.submodule {
|
|
|
|
options = {
|
|
|
|
host = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
example = "smtp.example.org";
|
|
|
|
description = ''
|
|
|
|
Hostname of SMTP server.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
port = mkOption {
|
2019-08-19 20:37:48 +02:00
|
|
|
type = types.nullOr types.port;
|
2018-06-26 23:41:30 +02:00
|
|
|
default = null;
|
|
|
|
example = 465;
|
|
|
|
description = ''
|
|
|
|
The port on which the SMTP server listens. If
|
|
|
|
<literal>null</literal> then the default port is used.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
tls = mkOption {
|
|
|
|
type = tlsModule;
|
2020-04-06 12:51:11 +02:00
|
|
|
default = { };
|
2018-06-26 23:41:30 +02:00
|
|
|
description = ''
|
|
|
|
Configuration for secure connections.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
maildirModule = types.submodule ({ config, ... }: {
|
|
|
|
options = {
|
|
|
|
path = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
|
|
|
Path to maildir directory where mail for this account is
|
|
|
|
stored. This is relative to the base maildir path.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
absPath = mkOption {
|
|
|
|
type = types.path;
|
|
|
|
readOnly = true;
|
|
|
|
internal = true;
|
|
|
|
default = "${cfg.maildirBasePath}/${config.path}";
|
|
|
|
description = ''
|
|
|
|
A convenience option whose value is the absolute path of
|
|
|
|
this maildir.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
2018-08-16 21:37:42 +02:00
|
|
|
mailAccountOpts = { name, config, ... }: {
|
2018-06-26 23:41:30 +02:00
|
|
|
options = {
|
|
|
|
name = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
readOnly = true;
|
|
|
|
description = ''
|
|
|
|
Unique identifier of the account. This is set to the
|
|
|
|
attribute name of the account configuration.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
primary = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = ''
|
|
|
|
Whether this is the primary account. Only one account may be
|
|
|
|
set as primary.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
flavor = mkOption {
|
2022-08-25 13:36:35 +02:00
|
|
|
type = types.enum [
|
|
|
|
"plain"
|
|
|
|
"gmail.com"
|
|
|
|
"runbox.com"
|
|
|
|
"fastmail.com"
|
|
|
|
"yandex.com"
|
|
|
|
"outlook.office365.com"
|
|
|
|
];
|
2018-06-26 23:41:30 +02:00
|
|
|
default = "plain";
|
|
|
|
description = ''
|
|
|
|
Some email providers have peculiar behavior that require
|
|
|
|
special treatment. This option is therefore intended to
|
|
|
|
indicate the nature of the provider.
|
|
|
|
</para><para>
|
|
|
|
When this indicates a specific provider then, for example,
|
2022-06-22 00:11:53 +02:00
|
|
|
the IMAP, SMTP, and JMAP server configuration may be set
|
2018-06-26 23:41:30 +02:00
|
|
|
automatically.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
address = mkOption {
|
|
|
|
type = types.strMatching ".*@.*";
|
|
|
|
example = "jane.doe@example.org";
|
|
|
|
description = "The email address of this account.";
|
|
|
|
};
|
|
|
|
|
2019-04-10 13:50:44 +02:00
|
|
|
aliases = mkOption {
|
|
|
|
type = types.listOf (types.strMatching ".*@.*");
|
2020-04-06 12:51:11 +02:00
|
|
|
default = [ ];
|
2019-04-10 13:50:44 +02:00
|
|
|
example = [ "webmaster@example.org" "admin@example.org" ];
|
|
|
|
description = "Alternative email addresses of this account.";
|
|
|
|
};
|
|
|
|
|
2018-06-26 23:41:30 +02:00
|
|
|
realName = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
example = "Jane Doe";
|
|
|
|
description = "Name displayed when sending mails.";
|
|
|
|
};
|
|
|
|
|
|
|
|
userName = mkOption {
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = null;
|
|
|
|
description = ''
|
|
|
|
The server username of this account. This will be used as
|
2022-06-22 00:11:53 +02:00
|
|
|
the SMTP, IMAP, and JMAP user name.
|
2018-06-26 23:41:30 +02:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
passwordCommand = mkOption {
|
|
|
|
type = types.nullOr (types.either types.str (types.listOf types.str));
|
|
|
|
default = null;
|
|
|
|
apply = p: if isString p then splitString " " p else p;
|
|
|
|
example = "secret-tool lookup email me@example.org";
|
|
|
|
description = ''
|
2018-08-21 00:19:33 +02:00
|
|
|
A command, which when run writes the account password on
|
|
|
|
standard output.
|
2018-06-26 23:41:30 +02:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
folders = mkOption {
|
|
|
|
type = types.submodule {
|
|
|
|
options = {
|
|
|
|
inbox = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "Inbox";
|
|
|
|
description = ''
|
|
|
|
Relative path of the inbox mail.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
sent = mkOption {
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = "Sent";
|
|
|
|
description = ''
|
|
|
|
Relative path of the sent mail folder.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
drafts = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "Drafts";
|
|
|
|
description = ''
|
|
|
|
Relative path of the drafts mail folder.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
trash = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "Trash";
|
|
|
|
description = ''
|
|
|
|
Relative path of the deleted mail folder.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
2020-04-06 12:51:11 +02:00
|
|
|
default = { };
|
2018-06-26 23:41:30 +02:00
|
|
|
description = ''
|
|
|
|
Standard email folders.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
imap = mkOption {
|
|
|
|
type = types.nullOr imapModule;
|
|
|
|
default = null;
|
|
|
|
description = ''
|
|
|
|
The IMAP configuration to use for this account.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2022-06-22 00:11:53 +02:00
|
|
|
jmap = mkOption {
|
|
|
|
type = types.nullOr jmapModule;
|
|
|
|
default = null;
|
|
|
|
description = ''
|
|
|
|
The JMAP configuration to use for this account.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2018-09-08 11:45:29 +02:00
|
|
|
signature = mkOption {
|
|
|
|
type = signatureModule;
|
2020-04-06 12:51:11 +02:00
|
|
|
default = { };
|
2018-09-08 11:45:29 +02:00
|
|
|
description = ''
|
|
|
|
Signature configuration.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
gpg = mkOption {
|
|
|
|
type = types.nullOr gpgModule;
|
|
|
|
default = null;
|
|
|
|
description = ''
|
|
|
|
GPG configuration.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2018-06-26 23:41:30 +02:00
|
|
|
smtp = mkOption {
|
|
|
|
type = types.nullOr smtpModule;
|
|
|
|
default = null;
|
|
|
|
description = ''
|
|
|
|
The SMTP configuration to use for this account.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
maildir = mkOption {
|
|
|
|
type = types.nullOr maildirModule;
|
|
|
|
defaultText = { path = "\${name}"; };
|
|
|
|
description = ''
|
|
|
|
Maildir configuration for this account.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkMerge [
|
|
|
|
{
|
|
|
|
name = name;
|
|
|
|
maildir = mkOptionDefault { path = "${name}"; };
|
|
|
|
}
|
2022-06-20 00:56:57 +02:00
|
|
|
|
2022-08-25 13:36:35 +02:00
|
|
|
(mkIf (config.flavor == "yandex.com") {
|
|
|
|
userName = mkDefault config.address;
|
|
|
|
|
|
|
|
imap = {
|
|
|
|
host = "imap.yandex.com";
|
|
|
|
port = 993;
|
|
|
|
tls.enable = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
smtp = {
|
|
|
|
host = "smtp.yandex.com";
|
|
|
|
port = 465;
|
|
|
|
tls.enable = true;
|
|
|
|
};
|
|
|
|
})
|
|
|
|
|
|
|
|
(mkIf (config.flavor == "outlook.office365.com") {
|
|
|
|
userName = mkDefault config.address;
|
|
|
|
|
|
|
|
imap = {
|
|
|
|
host = "outlook.office365.com";
|
|
|
|
port = 993;
|
|
|
|
tls.enable = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
smtp = {
|
2022-08-30 03:48:12 +02:00
|
|
|
host = "smtp.office365.com";
|
2022-08-25 13:36:35 +02:00
|
|
|
port = 587;
|
|
|
|
tls = {
|
|
|
|
enable = true;
|
|
|
|
useStartTls = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
})
|
|
|
|
|
2021-11-14 00:07:23 +01:00
|
|
|
(mkIf (config.flavor == "fastmail.com") {
|
|
|
|
userName = mkDefault config.address;
|
2022-06-20 00:56:57 +02:00
|
|
|
|
2021-11-14 00:07:23 +01:00
|
|
|
imap = {
|
|
|
|
host = "imap.fastmail.com";
|
|
|
|
port = 993;
|
|
|
|
};
|
2022-06-20 00:56:57 +02:00
|
|
|
|
|
|
|
smtp = {
|
|
|
|
host = "smtp.fastmail.com";
|
|
|
|
port = if config.smtp.tls.useStartTls then 587 else 465;
|
|
|
|
};
|
2022-06-22 00:11:53 +02:00
|
|
|
|
|
|
|
jmap = {
|
|
|
|
host = "fastmail.com";
|
|
|
|
sessionUrl = "https://jmap.fastmail.com/.well-known/jmap";
|
|
|
|
};
|
2021-11-14 00:07:23 +01:00
|
|
|
})
|
2022-06-20 00:56:57 +02:00
|
|
|
|
2018-08-06 12:10:57 +02:00
|
|
|
(mkIf (config.flavor == "gmail.com") {
|
|
|
|
userName = mkDefault config.address;
|
|
|
|
|
2021-06-27 00:29:42 +02:00
|
|
|
imap = {
|
|
|
|
host = "imap.gmail.com";
|
|
|
|
port = 993;
|
|
|
|
};
|
2018-08-06 12:10:57 +02:00
|
|
|
|
|
|
|
smtp = {
|
|
|
|
host = "smtp.gmail.com";
|
2018-09-02 03:01:18 +02:00
|
|
|
port = if config.smtp.tls.useStartTls then 587 else 465;
|
2018-08-06 12:10:57 +02:00
|
|
|
};
|
|
|
|
})
|
|
|
|
|
2018-06-26 23:41:30 +02:00
|
|
|
(mkIf (config.flavor == "runbox.com") {
|
2020-04-06 12:51:11 +02:00
|
|
|
imap = { host = "mail.runbox.com"; };
|
2018-06-26 23:41:30 +02:00
|
|
|
|
2020-04-06 12:51:11 +02:00
|
|
|
smtp = { host = "mail.runbox.com"; };
|
2018-06-26 23:41:30 +02:00
|
|
|
})
|
|
|
|
];
|
2018-08-16 21:37:42 +02:00
|
|
|
};
|
2018-06-26 23:41:30 +02:00
|
|
|
|
2020-04-06 12:51:11 +02:00
|
|
|
in {
|
2018-06-26 23:41:30 +02:00
|
|
|
options.accounts.email = {
|
2018-08-16 23:09:20 +02:00
|
|
|
certificatesFile = mkOption {
|
2021-08-02 20:23:50 +02:00
|
|
|
type = types.nullOr types.path;
|
2018-08-16 23:09:20 +02:00
|
|
|
default = "/etc/ssl/certs/ca-certificates.crt";
|
|
|
|
description = ''
|
|
|
|
Path to default file containing certificate authorities that
|
|
|
|
should be used to validate the connection authenticity. This
|
|
|
|
path may be overridden on a per-account basis.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2018-06-26 23:41:30 +02:00
|
|
|
maildirBasePath = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${config.home.homeDirectory}/Maildir";
|
|
|
|
defaultText = "$HOME/Maildir";
|
|
|
|
apply = p:
|
2020-04-06 12:51:11 +02:00
|
|
|
if hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}";
|
2018-06-26 23:41:30 +02:00
|
|
|
description = ''
|
|
|
|
The base directory for account maildir directories. May be a
|
|
|
|
relative path, in which case it is relative the home
|
|
|
|
directory.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
accounts = mkOption {
|
2020-06-16 00:45:20 +02:00
|
|
|
type = types.attrsOf (types.submodule mailAccountOpts);
|
2020-04-06 12:51:11 +02:00
|
|
|
default = { };
|
2018-06-26 23:41:30 +02:00
|
|
|
description = "List of email accounts.";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-04-06 12:51:11 +02:00
|
|
|
config = mkIf (cfg.accounts != { }) {
|
2018-06-26 23:41:30 +02:00
|
|
|
assertions = [
|
2020-04-06 12:51:11 +02:00
|
|
|
(let
|
|
|
|
primaries =
|
|
|
|
catAttrs "name" (filter (a: a.primary) (attrValues cfg.accounts));
|
|
|
|
in {
|
|
|
|
assertion = length primaries == 1;
|
|
|
|
message = "Must have exactly one primary mail account but found "
|
|
|
|
+ toString (length primaries) + optionalString (length primaries > 1)
|
|
|
|
(", namely " + concatStringsSep ", " primaries);
|
|
|
|
})
|
2018-06-26 23:41:30 +02:00
|
|
|
];
|
|
|
|
};
|
|
|
|
}
|