mirror of
https://github.com/nix-community/home-manager
synced 2024-11-10 21:29:48 +01:00
neomutt: Initial IMAP support (#4597)
neomutt: Updated options and added tests neomutt: Added test for individual mailbox type neomutt: Formatted code neomutt: Enable ssl_force_tls based on IMAP instead of SMTP neomutt: Applied suggestions from @chayleaf neomutt: fix breaking tests
This commit is contained in:
parent
c8842ff8f1
commit
f66e0c311b
9 changed files with 360 additions and 14 deletions
|
@ -17,6 +17,14 @@ let
|
||||||
default = null;
|
default = null;
|
||||||
description = "Name to display";
|
description = "Name to display";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type = mkOption {
|
||||||
|
type = types.nullOr (types.enum [ "maildir" "imap" ]);
|
||||||
|
example = "imap";
|
||||||
|
default = null;
|
||||||
|
description =
|
||||||
|
"Whether this mailbox is a maildir folder or an IMAP mailbox";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -75,6 +83,14 @@ in {
|
||||||
description = "Use a different name as mailbox name";
|
description = "Use a different name as mailbox name";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mailboxType = mkOption {
|
||||||
|
type = types.enum [ "maildir" "imap" ];
|
||||||
|
default = "maildir";
|
||||||
|
example = "imap";
|
||||||
|
description =
|
||||||
|
"Whether this account uses maildir folders or IMAP mailboxes";
|
||||||
|
};
|
||||||
|
|
||||||
extraMailboxes = mkOption {
|
extraMailboxes = mkOption {
|
||||||
type = with types; listOf (either str (submodule extraMailboxOptions));
|
type = with types; listOf (either str (submodule extraMailboxOptions));
|
||||||
default = [ ];
|
default = [ ];
|
||||||
|
|
|
@ -8,6 +8,59 @@ let
|
||||||
neomuttAccounts =
|
neomuttAccounts =
|
||||||
filter (a: a.neomutt.enable) (attrValues config.accounts.email.accounts);
|
filter (a: a.neomutt.enable) (attrValues config.accounts.email.accounts);
|
||||||
|
|
||||||
|
accountCommandNeeded = any (a:
|
||||||
|
a.neomutt.enable && (a.neomutt.mailboxType == "imap"
|
||||||
|
|| (any (m: !isString m && m.type == "imap") a.neomutt.extraMailboxes)))
|
||||||
|
(attrValues config.accounts.email.accounts);
|
||||||
|
|
||||||
|
accountCommand = let
|
||||||
|
imapAccounts = filter (a:
|
||||||
|
a.neomutt.enable && a.imap.host != null && a.userName != null
|
||||||
|
&& a.passwordCommand != null) (attrValues config.accounts.email.accounts);
|
||||||
|
accountCase = account:
|
||||||
|
let passwordCmd = toString account.passwordCommand;
|
||||||
|
in ''
|
||||||
|
${account.userName}@${account.imap.host})
|
||||||
|
found=1
|
||||||
|
username="${account.userName}"
|
||||||
|
password="$(${passwordCmd})"
|
||||||
|
;;'';
|
||||||
|
in pkgs.writeShellScriptBin "account-command.sh" ''
|
||||||
|
# Automatically set login variables based on the current account.
|
||||||
|
# This requires NeoMutt >= 2022-05-16
|
||||||
|
|
||||||
|
while [ ! -z "$1" ]; do
|
||||||
|
case "$1" in
|
||||||
|
--hostname)
|
||||||
|
shift
|
||||||
|
hostname="$1"
|
||||||
|
;;
|
||||||
|
--username)
|
||||||
|
shift
|
||||||
|
username="$1@"
|
||||||
|
;;
|
||||||
|
--type)
|
||||||
|
shift
|
||||||
|
type="$1"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
found=
|
||||||
|
case "''${username}''${hostname}" in
|
||||||
|
${concatMapStringsSep "\n" accountCase imapAccounts}
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -n "$found" ]; then
|
||||||
|
echo "username: $username"
|
||||||
|
echo "password: $password"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
sidebarModule = types.submodule {
|
sidebarModule = types.submodule {
|
||||||
options = {
|
options = {
|
||||||
enable = mkEnableOption "sidebar support";
|
enable = mkEnableOption "sidebar support";
|
||||||
|
@ -101,6 +154,21 @@ let
|
||||||
|
|
||||||
accountFilename = account: config.xdg.configHome + "/neomutt/" + account.name;
|
accountFilename = account: config.xdg.configHome + "/neomutt/" + account.name;
|
||||||
|
|
||||||
|
accountRootIMAP = account:
|
||||||
|
let
|
||||||
|
userName =
|
||||||
|
lib.optionalString (account.userName != null) "${account.userName}@";
|
||||||
|
port = lib.optionalString (account.imap.port != null)
|
||||||
|
":${toString account.imap.port}";
|
||||||
|
protocol = if account.imap.tls.enable then "imaps" else "imap";
|
||||||
|
in "${protocol}://${userName}${account.imap.host}${port}";
|
||||||
|
|
||||||
|
accountRoot = account:
|
||||||
|
if account.neomutt.mailboxType == "imap" then
|
||||||
|
accountRootIMAP account
|
||||||
|
else
|
||||||
|
account.maildir.absPath;
|
||||||
|
|
||||||
genCommonFolderHooks = account:
|
genCommonFolderHooks = account:
|
||||||
with account; {
|
with account; {
|
||||||
from = "'${address}'";
|
from = "'${address}'";
|
||||||
|
@ -128,12 +196,12 @@ let
|
||||||
smtp_pass = ''"`${passCmd}`"'';
|
smtp_pass = ''"`${passCmd}`"'';
|
||||||
};
|
};
|
||||||
|
|
||||||
genMaildirAccountConfig = account:
|
genAccountConfig = account:
|
||||||
with account;
|
with account;
|
||||||
let
|
let
|
||||||
folderHook = mapAttrsToList setOption (genCommonFolderHooks account
|
folderHook = mapAttrsToList setOption (genCommonFolderHooks account
|
||||||
// optionalAttrs cfg.changeFolderWhenSourcingAccount {
|
// optionalAttrs cfg.changeFolderWhenSourcingAccount {
|
||||||
folder = "'${account.maildir.absPath}'";
|
folder = "'${accountRoot account}'";
|
||||||
});
|
});
|
||||||
in ''
|
in ''
|
||||||
${concatStringsSep "\n" folderHook}
|
${concatStringsSep "\n" folderHook}
|
||||||
|
@ -145,29 +213,40 @@ let
|
||||||
"mailboxes"
|
"mailboxes"
|
||||||
else
|
else
|
||||||
''named-mailboxes "${account.neomutt.mailboxName}"'';
|
''named-mailboxes "${account.neomutt.mailboxName}"'';
|
||||||
extraMailboxes = concatMapStringsSep "\n" (extra:
|
mailroot = accountRoot account;
|
||||||
if isString extra then
|
hookName = if account.neomutt.mailboxType == "imap" then
|
||||||
''mailboxes "${account.maildir.absPath}/${extra}"''
|
"account-hook"
|
||||||
else if extra.name == null then
|
|
||||||
''mailboxes "${account.maildir.absPath}/${extra.mailbox}"''
|
|
||||||
else
|
else
|
||||||
''
|
"folder-hook";
|
||||||
named-mailboxes "${extra.name}" "${account.maildir.absPath}/${extra.mailbox}"'')
|
extraMailboxes = concatMapStringsSep "\n" (extra:
|
||||||
|
let
|
||||||
|
mailboxroot = if !isString extra && extra.type == "imap" then
|
||||||
|
accountRootIMAP account
|
||||||
|
else if !isString extra && extra.type == "maildir" then
|
||||||
|
account.maildir.absPath
|
||||||
|
else
|
||||||
|
mailroot;
|
||||||
|
in if isString extra then
|
||||||
|
''mailboxes "${mailboxroot}/${extra}"''
|
||||||
|
else if extra.name == null then
|
||||||
|
''mailboxes "${mailboxroot}/${extra.mailbox}"''
|
||||||
|
else
|
||||||
|
''named-mailboxes "${extra.name}" "${mailboxroot}/${extra.mailbox}"'')
|
||||||
account.neomutt.extraMailboxes;
|
account.neomutt.extraMailboxes;
|
||||||
in with account; ''
|
in with account; ''
|
||||||
# register account ${name}
|
# register account ${name}
|
||||||
${mailboxes} "${maildir.absPath}/${folders.inbox}"
|
${mailboxes} "${mailroot}/${folders.inbox}"
|
||||||
${extraMailboxes}
|
${extraMailboxes}
|
||||||
folder-hook ${maildir.absPath}/ " \
|
${hookName} ${mailroot}/ " \
|
||||||
source ${accountFilename account} "
|
source ${accountFilename account} "
|
||||||
'';
|
'';
|
||||||
|
|
||||||
mraSection = account:
|
mraSection = account:
|
||||||
with account;
|
with account;
|
||||||
if account.maildir != null then
|
if account.imap.host != null || account.maildir != null then
|
||||||
genMaildirAccountConfig account
|
genAccountConfig account
|
||||||
else
|
else
|
||||||
throw "Only maildir is supported at the moment";
|
throw "Only maildir and IMAP is supported at the moment";
|
||||||
|
|
||||||
optionsStr = attrs: concatStringsSep "\n" (mapAttrsToList setOption attrs);
|
optionsStr = attrs: concatStringsSep "\n" (mapAttrsToList setOption attrs);
|
||||||
|
|
||||||
|
@ -219,7 +298,7 @@ let
|
||||||
in ''
|
in ''
|
||||||
# Generated by Home Manager.
|
# Generated by Home Manager.
|
||||||
set ssl_force_tls = ${
|
set ssl_force_tls = ${
|
||||||
lib.hm.booleans.yesNo (smtp.tls.enable || smtp.tls.useStartTls)
|
lib.hm.booleans.yesNo (imap.tls.enable || imap.tls.useStartTls)
|
||||||
}
|
}
|
||||||
set certificate_file=${toString config.accounts.email.certificatesFile}
|
set certificate_file=${toString config.accounts.email.certificatesFile}
|
||||||
|
|
||||||
|
@ -366,7 +445,11 @@ in {
|
||||||
"source ${pkgs.neomutt}/share/doc/neomutt/vim-keys/vim-keys.rc"}
|
"source ${pkgs.neomutt}/share/doc/neomutt/vim-keys/vim-keys.rc"}
|
||||||
|
|
||||||
# Register accounts
|
# Register accounts
|
||||||
${concatMapStringsSep "\n" registerAccount neomuttAccounts}
|
${
|
||||||
|
optionalString (accountCommandNeeded) ''
|
||||||
|
set account_command = '${accountCommand}/bin/account-command.sh'
|
||||||
|
''
|
||||||
|
}${concatMapStringsSep "\n" registerAccount neomuttAccounts}
|
||||||
|
|
||||||
# Source primary account
|
# Source primary account
|
||||||
source ${accountFilename primary}
|
source ${accountFilename primary}
|
||||||
|
|
39
tests/modules/programs/neomutt/account-command.sh-expected
Normal file
39
tests/modules/programs/neomutt/account-command.sh-expected
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#!/nix/store/00000000000000000000000000000000-bash/bin/bash
|
||||||
|
# Automatically set login variables based on the current account.
|
||||||
|
# This requires NeoMutt >= 2022-05-16
|
||||||
|
|
||||||
|
while [ ! -z "$1" ]; do
|
||||||
|
case "$1" in
|
||||||
|
--hostname)
|
||||||
|
shift
|
||||||
|
hostname="$1"
|
||||||
|
;;
|
||||||
|
--username)
|
||||||
|
shift
|
||||||
|
username="$1@"
|
||||||
|
;;
|
||||||
|
--type)
|
||||||
|
shift
|
||||||
|
type="$1"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
found=
|
||||||
|
case "${username}${hostname}" in
|
||||||
|
home.manager@imap.example.com)
|
||||||
|
found=1
|
||||||
|
username="home.manager"
|
||||||
|
password="$(password-command)"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -n "$found" ]; then
|
||||||
|
echo "username: $username"
|
||||||
|
echo "password: $password"
|
||||||
|
fi
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
neomutt-simple = ./neomutt.nix;
|
neomutt-simple = ./neomutt.nix;
|
||||||
neomutt-with-msmtp = ./neomutt-with-msmtp.nix;
|
neomutt-with-msmtp = ./neomutt-with-msmtp.nix;
|
||||||
|
neomutt-with-imap = ./neomutt-with-imap.nix;
|
||||||
neomutt-not-primary = ./neomutt-not-primary.nix;
|
neomutt-not-primary = ./neomutt-not-primary.nix;
|
||||||
neomutt-with-binds = ./neomutt-with-binds.nix;
|
neomutt-with-binds = ./neomutt-with-binds.nix;
|
||||||
neomutt-with-binds-with-warning = ./neomutt-with-binds-with-warning.nix;
|
neomutt-with-binds-with-warning = ./neomutt-with-binds-with-warning.nix;
|
||||||
|
@ -9,6 +10,7 @@
|
||||||
neomutt-with-gpg = ./neomutt-with-gpg.nix;
|
neomutt-with-gpg = ./neomutt-with-gpg.nix;
|
||||||
neomutt-no-folder-change = ./neomutt-no-folder-change.nix;
|
neomutt-no-folder-change = ./neomutt-no-folder-change.nix;
|
||||||
neomutt-with-named-mailboxes = ./neomutt-with-named-mailboxes.nix;
|
neomutt-with-named-mailboxes = ./neomutt-with-named-mailboxes.nix;
|
||||||
|
neomutt-with-imap-type-mailboxes = ./neomutt-with-imap-type-mailboxes.nix;
|
||||||
neomutt-with-signature = ./neomutt-with-signature.nix;
|
neomutt-with-signature = ./neomutt-with-signature.nix;
|
||||||
neomutt-with-signature-command = ./neomutt-with-signature-command.nix;
|
neomutt-with-signature-command = ./neomutt-with-signature-command.nix;
|
||||||
neomutt-with-starttls = ./neomutt-with-starttls.nix;
|
neomutt-with-starttls = ./neomutt-with-starttls.nix;
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Generated by Home Manager.
|
||||||
|
set ssl_force_tls = yes
|
||||||
|
set certificate_file=/etc/ssl/certs/ca-certificates.crt
|
||||||
|
|
||||||
|
# GPG section
|
||||||
|
set crypt_use_gpgme = yes
|
||||||
|
set crypt_autosign = no
|
||||||
|
set crypt_opportunistic_encrypt = no
|
||||||
|
set pgp_use_gpg_agent = yes
|
||||||
|
set mbox_type = Maildir
|
||||||
|
set sort = "threads"
|
||||||
|
|
||||||
|
# MTA section
|
||||||
|
set smtp_pass="`password-command`"
|
||||||
|
set smtp_url='smtps://home.manager@smtp.example.com'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# MRA section
|
||||||
|
set folder='imaps://home.manager@imap.example.com:993'
|
||||||
|
set from='hm@example.com'
|
||||||
|
set postponed='+Drafts'
|
||||||
|
set realname='H. M. Test'
|
||||||
|
set record='+Sent'
|
||||||
|
set spoolfile='+Inbox'
|
||||||
|
set trash='+Trash'
|
||||||
|
|
||||||
|
|
||||||
|
# Extra configuration
|
||||||
|
color status cyan default
|
||||||
|
|
||||||
|
|
||||||
|
unset signature
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Generated by Home Manager.
|
||||||
|
set header_cache = "/home/hm-user/.cache/neomutt/headers/"
|
||||||
|
set message_cachedir = "/home/hm-user/.cache/neomutt/messages/"
|
||||||
|
set editor = "$EDITOR"
|
||||||
|
set implicit_autoview = yes
|
||||||
|
|
||||||
|
alternative_order text/enriched text/plain text
|
||||||
|
|
||||||
|
set delete = yes
|
||||||
|
|
||||||
|
# Binds
|
||||||
|
|
||||||
|
|
||||||
|
# Macros
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Register accounts
|
||||||
|
set account_command = '/nix/store/00000000000000000000000000000000-account-command.sh/bin/account-command.sh'
|
||||||
|
# register account hm@example.com
|
||||||
|
mailboxes "imaps://home.manager@imap.example.com:993/Inbox"
|
||||||
|
|
||||||
|
account-hook imaps://home.manager@imap.example.com:993/ " \
|
||||||
|
source /home/hm-user/.config/neomutt/hm@example.com "
|
||||||
|
|
||||||
|
|
||||||
|
# Source primary account
|
||||||
|
source /home/hm-user/.config/neomutt/hm@example.com
|
||||||
|
|
||||||
|
# Extra configuration
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
# Generated by Home Manager.
|
||||||
|
set header_cache = "/home/hm-user/.cache/neomutt/headers/"
|
||||||
|
set message_cachedir = "/home/hm-user/.cache/neomutt/messages/"
|
||||||
|
set editor = "$EDITOR"
|
||||||
|
set implicit_autoview = yes
|
||||||
|
|
||||||
|
alternative_order text/enriched text/plain text
|
||||||
|
|
||||||
|
set delete = yes
|
||||||
|
|
||||||
|
# Binds
|
||||||
|
|
||||||
|
|
||||||
|
# Macros
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Register accounts
|
||||||
|
set account_command = '/nix/store/00000000000000000000000000000000-account-command.sh/bin/account-command.sh'
|
||||||
|
# register account hm@example.com
|
||||||
|
named-mailboxes "someCustomName" "/home/hm-user/Mail/hm@example.com/Inbox"
|
||||||
|
mailboxes "/home/hm-user/Mail/hm@example.com/Sent"
|
||||||
|
named-mailboxes "Spam" "imaps://home.manager@imap.example.com:993/Junk Email"
|
||||||
|
mailboxes "/home/hm-user/Mail/hm@example.com/Trash"
|
||||||
|
folder-hook /home/hm-user/Mail/hm@example.com/ " \
|
||||||
|
source /home/hm-user/.config/neomutt/hm@example.com "
|
||||||
|
|
||||||
|
|
||||||
|
# Source primary account
|
||||||
|
source /home/hm-user/.config/neomutt/hm@example.com
|
||||||
|
|
||||||
|
# Extra configuration
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [ ../../accounts/email-test-accounts.nix ];
|
||||||
|
|
||||||
|
config = {
|
||||||
|
accounts.email.accounts = {
|
||||||
|
"hm@example.com" = {
|
||||||
|
notmuch.enable = true;
|
||||||
|
neomutt = {
|
||||||
|
enable = true;
|
||||||
|
extraConfig = ''
|
||||||
|
color status cyan default
|
||||||
|
'';
|
||||||
|
mailboxName = "someCustomName";
|
||||||
|
extraMailboxes = [
|
||||||
|
"Sent"
|
||||||
|
{
|
||||||
|
mailbox = "Junk Email";
|
||||||
|
name = "Spam";
|
||||||
|
type = "imap";
|
||||||
|
}
|
||||||
|
{ mailbox = "Trash"; }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
imap.port = 993;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.neomutt = {
|
||||||
|
enable = true;
|
||||||
|
vimKeys = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
test.stubs.neomutt = { };
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/.config/neomutt/neomuttrc
|
||||||
|
assertFileExists home-files/.config/neomutt/hm@example.com
|
||||||
|
assertFileContent $(normalizeStorePaths home-files/.config/neomutt/neomuttrc) ${
|
||||||
|
./neomutt-with-imap-type-mailboxes-expected.conf
|
||||||
|
}
|
||||||
|
assertFileContent home-files/.config/neomutt/hm@example.com ${
|
||||||
|
./hm-example.com-expected
|
||||||
|
}
|
||||||
|
|
||||||
|
confFile=$(grep -o \
|
||||||
|
'/nix/store/.*-account-command.sh/bin/account-command.sh' \
|
||||||
|
$TESTED/home-files/.config/neomutt/neomuttrc)
|
||||||
|
assertFileContent "$(normalizeStorePaths "$confFile")" ${
|
||||||
|
./account-command.sh-expected
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
44
tests/modules/programs/neomutt/neomutt-with-imap.nix
Normal file
44
tests/modules/programs/neomutt/neomutt-with-imap.nix
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [ ../../accounts/email-test-accounts.nix ];
|
||||||
|
|
||||||
|
config = {
|
||||||
|
accounts.email.accounts = {
|
||||||
|
"hm@example.com" = {
|
||||||
|
neomutt = {
|
||||||
|
enable = true;
|
||||||
|
mailboxType = "imap";
|
||||||
|
extraConfig = ''
|
||||||
|
color status cyan default
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
imap.port = 993;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.neomutt.enable = true;
|
||||||
|
|
||||||
|
test.stubs.neomutt = { };
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/.config/neomutt/neomuttrc
|
||||||
|
assertFileExists home-files/.config/neomutt/hm@example.com
|
||||||
|
assertFileContent $(normalizeStorePaths home-files/.config/neomutt/neomuttrc) ${
|
||||||
|
./neomutt-with-imap-expected.conf
|
||||||
|
}
|
||||||
|
assertFileContent home-files/.config/neomutt/hm@example.com ${
|
||||||
|
./hm-example.com-imap-expected.conf
|
||||||
|
}
|
||||||
|
|
||||||
|
confFile=$(grep -o \
|
||||||
|
'/nix/store/.*-account-command.sh/bin/account-command.sh' \
|
||||||
|
$TESTED/home-files/.config/neomutt/neomuttrc)
|
||||||
|
assertFileContent "$(normalizeStorePaths "$confFile")" ${
|
||||||
|
./account-command.sh-expected
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue