{ lib, config, pkgs, inputs, ... }: with lib; let cfg = config.modules.email; secretsDirectory = "${(builtins.toString inputs.nix-private)}/secrets"; in { options.modules.email = { enable = mkEnableOption "Enable email accounts configuration"; accountConfigs = mkOption { type = types.attrsOf types.attrs; default = false; description = "List of account variables used to create accounts"; }; primary = mkOption { type = types.str; default = false; description = "name of primary account"; }; }; config = mkIf cfg.enable { sops = let secretList = lib.mapAttrs' ( name: value: nameValuePair ( value.secret.key ) ({ sopsFile = "${secretsDirectory}/${value.secret.file}"; }) ) cfg.accountConfigs; in { secrets = secretList; }; accounts.email = let defaultSetting = { mbsync = { enable = true; create = "maildir"; expunge = "both"; remove = "both"; }; msmtp = { enable = true; }; notmuch = { enable = true; }; neomutt = { enable = true; showDefaultMailbox = false; }; }; accountsList = lib.mapAttrs ( name: value: lib.recursiveUpdate defaultSetting value.config ) cfg.accountConfigs; in { maildirBasePath = "mail"; accounts = lib.recursiveUpdate accountsList { "${cfg.primary}".primary = true; }; }; programs.afew = let mailMoverRules = lib.mergeAttrsList ( lib.attrsets.mapAttrsToList ( n: v: if lib.hasAttrByPath ["afew" "mailMover"] v then v.afew.mailMover else {} ) cfg.accountConfigs); mailFilterRules = lib.flatten ( lib.attrsets.mapAttrsToList ( n: v: if lib.hasAttrByPath ["afew" "filters"] v then v.afew.filters else [] ) cfg.accountConfigs); in { enable = true; extraConfig = '' [FolderNameFilter] folder_explicit_list = archives folder_transforms = archives:archive maildir_separator = / [MailMover] folders = ${lib.concatStringsSep " " (lib.unique (lib.mapAttrsToList (n: v: "${n}") mailMoverRules))} rename = True ${lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: "${n} = ${toString v}") mailMoverRules)} [SpamFilter] [KillThreadsFilter] [ArchiveSentMailsFilter] sent_tag = sent [InboxFilter] ${lib.concatImapStrings (p: e: "\n\n[Filter.${toString p}]\n ${lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: "${n} = ${v}") e)}") mailFilterRules} ''; }; programs.neomutt = let accountMacros = lib.imap1 ( i: elem: elem // { map = ["index" "pager"]; key = ""; }) ( lib.attrsets.mapAttrsToList ( n: _: { "action" = "source ~/.config/neomutt/${n}=InboxUnread";} ) cfg.accountConfigs); in { enable = true; unmailboxes = true; editor = "nvim +/^$/ +':nohl'"; settings = { sleep_time = "1"; mbox_type = "Maildir"; header_color_partial = "yes"; duplicate_threads = "yes"; index_format = "'%4C| %24.24?GS?%F %GS &%F? %?GR?%GR &%?GU?%GU & ??%?GA?%GA & ?%?GE?%GE & ?%?M?󰘕 %s&%s? %* %?g?  %g? %<[y?%<[m?%<[d?%9[%H:%M ]&%9[%a %d ]>&%9[%b %d ]>&%9[%m/%y ]>'"; sort_aux = "last-date-sent"; mail_check = "120"; hidden_tags = "inbox,unread,draft,flagged,passed,replied,signed,encrypted,attachment,sent"; markers = "no"; wrap = "90"; smart_wrap = "yes"; reflow_text = "yes"; reflow_wrap = "90"; text_flowed = "yes"; search_context = "3"; pager_context = "5"; pager_index_lines = "10"; rfc2047_parameters = "yes"; edit_headers = "yes"; send_charset = "utf-8"; envelope_from = "yes"; my_status = "' %o/%m  | %l 󰉉 | %f %* Sort: %s-%S Pos: %P '"; my_pager = "'  %F |  %s %* Pos: %P '"; compose_format = "' COMPOSE  %a | 󰉉 %l'"; query_command = "'${pkgs.khard}/bin/khard email --parsable --search-in-source-files %s'"; }; extraConfig = '' ${(builtins.readFile ./files/theme.muttrc)} charset-hook ^iso-8859-1$ cp1252 ignore * unignore from date subject to cc bcc tags user-agent x-mailer auto_view text/x-vcard text/html text/enriched text/calendar alternative_order text/html text/enriched text/plain text/* tag-transforms "attachment" "󰁦" \ "encrypted" "󱧈" \ "signed" "󱅞" \ "unread" "" \ "replied" "" tag-formats "attachment" "GA" \ "encrypted" "GE" \ "signed" "GS" \ "unread" "GU" \ "replied" "GR" ''; binds = [ { map = [ "attach" "browser" "index" "pager" ]; key = "g"; action = "noop"; } { map = [ "attach" "browser" "index" "pager" ]; key = "G"; action = "noop"; } { map = [ "index" ]; key = "q"; action = "noop";} { map = [ "pager" ]; key = "Q"; action = "noop";} { map = [ "attach" "browser" "index" ]; key = "gg"; action = "first-entry";} { map = [ "attach" "browser" "index" ]; key = "G"; action = "last-entry";} { map = [ "pager" ]; key = "gg"; action = "top"; } { map = [ "pager" ]; key = "G"; action = "bottom"; } { map = [ "pager" ]; key = "k"; action = "previous-line"; } { map = [ "pager" ]; key = "j"; action = "next-line"; } # Scrolling { map = [ "attach" "browser" "pager" "index" ]; key = "\\CF"; action = "next-page";} { map = [ "attach" "browser" "pager" "index" ]; key = "\\CB"; action = "previous-page";} { map = [ "attach" "browser" "pager" "index" ]; key = "\\Cu"; action = "half-up";} { map = [ "attach" "browser" "pager" "index" ]; key = "\\Cd"; action = "half-down";} { map = [ "browser" "pager" ]; key = "\\Ce"; action = "next-line";} { map = [ "browser" "pager" ]; key = "\\Cy"; action = "previous-line";} { map = [ "index" ]; key = "\\Ce"; action = "next-line";} { map = [ "index" ]; key = "\\Cy"; action = "previous-line";} # Delete { map = [ "pager" "index" ]; key = "d "; action = "noop";} { map = [ "pager" "index" ]; key = "dd "; action = "delete-message";} # Reply { map =[ "pager" "index" ]; key = "R "; action = "group-reply";} # sidebar { map = [ "index" "pager" ]; key = ""; action = "sidebar-toggle-visible";} { map = [ "index" "pager" ]; key = "{"; action = "sidebar-prev";} { map = [ "index" "pager" ]; key = "}"; action = "sidebar-next";} { map = [ "index" "pager" ]; key = "|"; action = "sidebar-open";} # open virtual folder { map = [ "index" "pager" ]; key = "X"; action = "noop";} { map = [ "index" "pager" ]; key = "X"; action = "change-vfolder";} # read entire thread of the current message { map = [ "index" "pager" ]; key = "+"; action = "entire-thread";} # generate virtual folder from query { map = [ "index" "pager" ]; key = "\\eX"; action = "vfolder-from-query";} # generate virtual folder from query with time window { map = [ "index" ]; key = "<"; action = "vfolder-window-backward";} { map = [ "index" ]; key = ">"; action = "vfolder-window-forward";} { map = [ "index" "pager" ]; key = "\\CD"; action = "modify-tags";} # Editor { map = [ "editor" ]; key = ""; action = "complete-query";} { map = [ "editor" ]; key = "^T "; action = "complete";} ]; macros = [ #Define some macros here ] ++ accountMacros; }; programs.mbsync = { enable = true; }; services.mbsync = { enable = true; postExec = "${pkgs.notmuch}/bin/notmuch new"; }; programs.notmuch = { enable = true; new.tags = [ "new" ]; hooks.postNew = '' ${pkgs.afew}/bin/afew --tag --new ${pkgs.afew}/bin/afew --move --all ''; }; programs.msmtp = { enable = true; }; }; }