{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.programs.notmuch;
mkIniKeyValue = key: value:
let
tweakVal = v:
if isString v then v
else if isList v then concatMapStringsSep ";" tweakVal v
else if isBool v then (if v then "true" else "false")
else toString v;
in
"${key}=${tweakVal value}";
notmuchIni =
recursiveUpdate
{
database = {
path = config.accounts.email.maildirBasePath;
};
maildir = {
synchronize_flags = cfg.maildir.synchronizeFlags;
};
new = {
ignore = cfg.new.ignore;
tags = cfg.new.tags;
};
user =
let
accounts =
filter (a: a.notmuch.enable)
(attrValues config.accounts.email.accounts);
primary = filter (a: a.primary) accounts;
secondaries = filter (a: !a.primary) accounts;
in {
name = catAttrs "realName" primary;
primary_email = catAttrs "address" primary;
other_email = catAttrs "aliases" primary
++ catAttrs "address" secondaries
++ catAttrs "aliases" secondaries;
};
search = {
exclude_tags = cfg.search.excludeTags;
};
}
cfg.extraConfig;
in
{
options = {
programs.notmuch = {
enable = mkEnableOption "Notmuch mail indexer";
new = mkOption {
type = types.submodule {
options = {
ignore = mkOption {
type = types.listOf types.str;
default = [];
description = ''
A list to specify files and directories that will not be
searched for messages by notmuch new.
'';
};
tags = mkOption {
type = types.listOf types.str;
default = [ "unread" "inbox" ];
example = [ "new" ];
description = ''
A list of tags that will be added to all messages
incorporated by notmuch new.
'';
};
};
};
default = {};
description = ''
Options related to email processing performed by
notmuch new.
'';
};
extraConfig = mkOption {
type = types.attrsOf (types.attrsOf types.str);
default = {};
description = ''
Options that should be appended to the notmuch configuration file.
'';
};
hooks = {
preNew = mkOption {
type = types.lines;
default = "";
example = "mbsync --all";
description = ''
Bash statements run before scanning or importing new
messages into the database.
'';
};
postNew = mkOption {
type = types.lines;
default = "";
example = ''
notmuch tag +nixos -- tag:new and from:nixos1@discoursemail.com
'';
description = ''
Bash statements run after new messages have been imported
into the database and initial tags have been applied.
'';
};
postInsert = mkOption {
type = types.lines;
default = "";
description = ''
Bash statements run after a message has been inserted
into the database and initial tags have been applied.
'';
};
};
maildir = {
synchronizeFlags = mkOption {
type = types.bool;
default = true;
description = ''
Whether to synchronize Maildir flags.
'';
};
};
search = {
excludeTags = mkOption {
type = types.listOf types.str;
default = [ "deleted" "spam" ];
example = [ "trash" "spam" ];
description = ''
A list of tags that will be excluded from search results by
default. Using an excluded tag in a query will override that
exclusion.
'';
};
};
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = notmuchIni.user.name != [];
message = "notmuch: Must have a user name set.";
}
{
assertion = notmuchIni.user.primary_email != [];
message = "notmuch: Must have a user primary email address set.";
}
];
home.packages = [ pkgs.notmuch ];
home.sessionVariables = {
NOTMUCH_CONFIG = "${config.xdg.configHome}/notmuch/notmuchrc";
NMBGIT = "${config.xdg.dataHome}/notmuch/nmbug";
};
xdg.configFile."notmuch/notmuchrc".text =
let
toIni = generators.toINI { mkKeyValue = mkIniKeyValue; };
in
"# Generated by Home Manager.\n\n"
+ toIni notmuchIni;
home.file =
let
hook = name: cmds:
{
"${notmuchIni.database.path}/.notmuch/hooks/${name}".source =
pkgs.writeShellScript name ''
export PATH="${pkgs.notmuch}/bin''${PATH:+:}$PATH"
export NOTMUCH_CONFIG="${config.xdg.configHome}/notmuch/notmuchrc"
export NMBGIT="${config.xdg.dataHome}/notmuch/nmbug"
${cmds}
'';
};
in
optionalAttrs (cfg.hooks.preNew != "")
(hook "pre-new" cfg.hooks.preNew)
//
optionalAttrs (cfg.hooks.postNew != "")
(hook "post-new" cfg.hooks.postNew)
//
optionalAttrs (cfg.hooks.postInsert != "")
(hook "post-insert" cfg.hooks.postInsert);
};
}