diff options
| author | Akshay Nair <phenax5@gmail.com> | 2025-05-24 17:40:28 +0530 |
|---|---|---|
| committer | Akshay Nair <phenax5@gmail.com> | 2025-05-24 17:41:00 +0530 |
| commit | ce0a366e8ba58fb967d4270e9c0e7d3ba759c759 (patch) | |
| tree | e2db6bcce4eb29bcb92e8d64502d76cf6bc2b95c /modules | |
| parent | 5fc036f8de3c55bea6a5853bdd35ca65f168a48e (diff) | |
| download | nixos-config-ce0a366e8ba58fb967d4270e9c0e7d3ba759c759.tar.gz nixos-config-ce0a366e8ba58fb967d4270e9c0e7d3ba759c759.zip | |
Add setup for notmuch+lieer+aerc for email
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/email/.gitignore | 1 | ||||
| -rw-r--r-- | modules/email/aerc-binds.conf | 140 | ||||
| -rw-r--r-- | modules/email/aerc.conf | 23 | ||||
| -rw-r--r-- | modules/email/aerc.home.nix | 61 | ||||
| -rw-r--r-- | modules/email/aerc.theme.nix | 51 | ||||
| -rw-r--r-- | modules/email/mailbox-sync.module.nix | 70 | ||||
| -rw-r--r-- | modules/email/query-map.conf | 9 |
7 files changed, 355 insertions, 0 deletions
diff --git a/modules/email/.gitignore b/modules/email/.gitignore new file mode 100644 index 0000000..a211cae --- /dev/null +++ b/modules/email/.gitignore @@ -0,0 +1 @@ +private.nix diff --git a/modules/email/aerc-binds.conf b/modules/email/aerc-binds.conf new file mode 100644 index 0000000..15d3a49 --- /dev/null +++ b/modules/email/aerc-binds.conf @@ -0,0 +1,140 @@ +<C-p> = :prev-tab<Enter> +<C-n> = :next-tab<Enter> +<C-t> = :term<Enter> +? = :help keys<Enter> +<C-c> = :prompt 'Quit?' quit<Enter> +<C-q> = :prompt 'Quit?' quit<Enter> +<C-z> = :suspend<Enter> + + + + +[messages] +q = :prompt 'Quit?' quit<Enter> + +a = :read<Enter> +A = :unread<Enter> +i = :tag +important<Enter> +I = :tag -important<Enter> + +<Enter> = :view<Enter> + +j = :next<Enter> +k = :prev<Enter> +<C-d> = :next 50%<Enter> +<C-f> = :next 100%<Enter> +<C-u> = :prev 50%<Enter> +<C-b> = :prev 100%<Enter> +g = :select 0<Enter> +G = :select -1<Enter> + +J = :next-folder<Enter> +K = :prev-folder<Enter> + +v = :mark -t<Enter> +<Space> = :mark -t<Enter>:next<Enter> +V = :mark -v<Enter> + +T = :toggle-threads<Enter> +za = :fold -t<Enter> + +C = :compose<Enter> + +rr = :reply -a<Enter> +Rr = :reply<Enter> + +! = :term<space> +| = :pipe<space> + +/ = :search<space> +\ = :filter<space> +n = :next-result<Enter> +N = :prev-result<Enter> +<Esc> = :clear<Enter> + +s = :split<Enter> +S = :vsplit<Enter> + +[messages:folder=Drafts] +<Enter> = :recall<Enter> + + + + +[view] +/ = :toggle-key-passthrough<Enter>/ +q = :close<Enter> +o = :open<Enter> +S = :save<space> +| = :pipe<space> +D = :delete<Enter> + +<C-l> = :open-link <space> + +f = :forward<Enter> +rr = :reply -a<Enter> +Rr = :reply<Enter> + +H = :toggle-headers<Enter> +<C-k> = :prev-part<Enter> +<C-j> = :next-part<Enter> +J = :next<Enter> +K = :prev<Enter> + + + + +[view::passthrough] +$noinherit = true +$ex = <C-x> +<Esc> = :toggle-key-passthrough<Enter> + + + + +[compose] +$noinherit = true +$ex = <C-x> +$complete = <C-o> +<C-k> = :prev-field<Enter> +<C-j> = :next-field<Enter> +<tab> = :next-field<Enter> +<backtab> = :prev-field<Enter> +<C-p> = :prev-tab<Enter> +<C-n> = :next-tab<Enter> + + + + +[compose::editor] +$noinherit = true +$ex = <C-x> +<C-k> = :prev-field<Enter> +<C-j> = :next-field<Enter> +<C-p> = :prev-tab<Enter> +<C-n> = :next-tab<Enter> + + + + +[compose::review] +# Inline comments are used as descriptions on the review screen +y = :send<Enter> # Send +n = :abort<Enter> # Abort (discard message, no confirmation) +p = :preview<Enter> # Preview message +e = :edit<Enter> # Edit (body and headers) +a = :attach<space> # Add attachment +d = :detach<space> # Remove attachment +P = :postpone<Enter> # Postpone + + + + + +[terminal] +$noinherit = true +$ex = <C-x> + +<C-p> = :prev-tab<Enter> +<C-n> = :next-tab<Enter> + diff --git a/modules/email/aerc.conf b/modules/email/aerc.conf new file mode 100644 index 0000000..86982ae --- /dev/null +++ b/modules/email/aerc.conf @@ -0,0 +1,23 @@ +[general] +enable-osc8 = true +unsafe-accounts-conf = true + +[ui] +auto-mark-read = true + +[viewer] +parse-http-links = true + +[compose] +editor = nvim +file-picker-cmd = lf -selection-path=%f + +[filters] +text/plain=bat -f --paging=never --file-name="$AERC_SUBJECT ($AERC_FROM)" --style=header,grid +text/html=! w3m -I UTF-8 -T text/html +text/*=bat -fP --file-name="$AERC_FILENAME" --style=plain + +[openers] +image/*=sxiv {} +application/pdf=zathura {} + diff --git a/modules/email/aerc.home.nix b/modules/email/aerc.home.nix new file mode 100644 index 0000000..7dcd99e --- /dev/null +++ b/modules/email/aerc.home.nix @@ -0,0 +1,61 @@ +{ config, ... }: +# Create private.nix with work.email, work.name +# Setup with `notmuch setup` +# Authenticate with `take ~/mail/account.gmail/ && gmi init <email>` +let + private = import ./private.nix; + theme = import ./aerc.theme.nix; + maildir = "${config.home.homeDirectory}/mail"; + work-maildir = "${maildir}/account.gmail"; +in { + imports = [ ./mailbox-sync.module.nix ]; + + services.mailbox-sync = { + enable = true; + name = "work"; + maildir = work-maildir; + sync.frequency = "*:0/5"; + notify.enable = true; + }; + + programs.notmuch = { + enable = true; + new = { + tags = ["new"]; + ignore = ["/.*[.](json|lock|bak)$/"]; + }; + extraConfig = { + database = { + path = maildir; + }; + user = { + name = private.work.name; + primary_email = private.work.email; + }; + search = { + exclude_tags = "ignored"; + }; + }; + }; + + programs.aerc = { + enable = true; + + extraAccounts.Work = { + from = "${private.work.name} <${private.work.email}>"; + source = "notmuch://${maildir}"; + outgoing = "gmi send -t -C ${work-maildir}"; + query-map = "${./query-map.conf}"; + folders-sort = "Inbox,Unread,Important,_sent,_spam"; + default = "INBOX"; + copy-to = "Sent"; + postpone = "[Gmail]/Drafts"; + cache-headers = true; + }; + + extraConfig = builtins.readFile ./aerc.conf; + extraBinds = builtins.readFile ./aerc-binds.conf; + + stylesets.default = theme; + }; +} diff --git a/modules/email/aerc.theme.nix b/modules/email/aerc.theme.nix new file mode 100644 index 0000000..f2f525d --- /dev/null +++ b/modules/email/aerc.theme.nix @@ -0,0 +1,51 @@ +let + accent = "#4f3aA3"; +in { + "title.bg" = accent; + "title.fg" = "black"; + "title.bold" = true; + "header.bold" = true; + "header.fg" = accent; + "tab.bold" = true; + "tab.selected.fg" = "white"; + "tab.selected.bg" = accent; + "tab.selected.bold" = true; + "dirlist*.selected.bg" = accent; + "dirlist*.selected.fg" = "white"; + "dirlist*.selected.bold" = false; + "*error.bold" = true; + "*error.fg" = "red"; + "*warning.fg" = "yellow"; + "*success.fg" = "green"; + "statusline_default.bg" = "#303030"; + "statusline_error.fg" = "red"; + "msglist_unread.fg" = "#ffffff"; + "msglist_unread.bold" = true; + "msglist_deleted.fg" = "#666666"; + "msglist_*.selected.bg" = accent; + "msglist_marked.fg" = "black"; + "msglist_marked.selected.fg" = "black"; + "msglist_marked.bg" = "#BD93F9"; + "msglist_marked.selected.bg" = "#9956f5"; + "completion_pill.reverse" = false; + "selector_focused.bold" = false; + "selector_focused.bg" = accent; + "selector_focused.fg" = "white"; + "selector_chooser.bold" = false; + "selector_chooser.bg" = accent; + "selector_chooser.fg" = "white"; + "default.selected.bold" = false; + "default.selected.fg" = "white"; + "default.selected.bg" = accent; + "completion_default.selected.bg" = accent; + "completion_default.selected.fg" = "white"; + "part_filename.bold" = true; + "part_mimetype.fg" = accent; + "part_filename.selected.bg" = accent; + "part_filename.selected.fg" = "white"; + "part_mimetype.selected.bg" = accent; + "part_mimetype.selected.fg" = "white"; + "part_mimetype.selected.bold" = true; + "part_switcher.selected.bg" = accent; + "part_switcher.selected.fg" = "white"; +} diff --git a/modules/email/mailbox-sync.module.nix b/modules/email/mailbox-sync.module.nix new file mode 100644 index 0000000..ad5f94e --- /dev/null +++ b/modules/email/mailbox-sync.module.nix @@ -0,0 +1,70 @@ +{ config, pkgs, lib, ... }: +with lib; +let + cfg = config.services.mailbox-sync; + + notmuch = "${pkgs.notmuch}/bin/notmuch"; + gmi = "${pkgs.lieer}/bin/gmi"; + notify-send = "${pkgs.libnotify}/bin/notify-send"; + jq = "${pkgs.jq}/bin/jq"; + + notify-script = '' + emails=$(${notmuch} search --format=json '${cfg.notify.filter}' \ + | ${jq} -r '.[0:5] | map("* " + .subject + " (tag: " + (.tags | join(" ")) + ")") | join("\n\n")'); + + # Notify + ${notify-send} --app-name=notmuch "New mail baybey ($new_mail_count)" "$emails"; + ''; + + sync-script = '' + #!${pkgs.bash}/bin/bash + set -eu -o pipefail; + + ${gmi} sync; + + new_mail_count=$(${notmuch} count '${cfg.notify.filter}'); + if [ $new_mail_count = 0 ]; then + echo "No new mail"; + else + ${if cfg.notify.enable then notify-script else ""} + fi + + ${notmuch} tag -new -- tag:new; + ''; + + service-unit = { + Unit.ConditionPathExists = "${cfg.maildir}/.gmailieer.json"; + Service = { + Type = "oneshot"; + ExecStart = "${pkgs.writeScript "mailbox-sync-script" sync-script}"; + WorkingDirectory = cfg.maildir; + Environment = "NOTMUCH_CONFIG=${config.xdg.configHome}/notmuch/default/config"; + }; + }; + + timer-unit = { + Timer = { + OnCalendar = cfg.sync.frequency; + RandomizedDelaySec = 30; + }; + Install.WantedBy = [ "timers.target" ]; + }; +in { + options.services.mailbox-sync = { + enable = mkEnableOption "mailbox sync"; + name = mkOption { type = types.str; default = "default"; }; + maildir = mkOption { type = types.str; }; + sync.frequency = mkOption { type = types.str; default = "*:0/5"; }; + notify.enable = mkEnableOption "notify on new mail"; + notify.filter = mkOption { + type = types.str; + default = "tag:inbox and tag:unread and tag:new"; + }; + }; + + config = mkIf cfg.enable { + programs.lieer.enable = true; + systemd.user.services."mailbox-sync-${cfg.name}" = service-unit; + systemd.user.timers."mailbox-sync-${cfg.name}" = timer-unit; + }; +} diff --git a/modules/email/query-map.conf b/modules/email/query-map.conf new file mode 100644 index 0000000..fe14b08 --- /dev/null +++ b/modules/email/query-map.conf @@ -0,0 +1,9 @@ +Inbox=tag:inbox and not tag:archived and not tag:sent and not tag:deleted and not tag:spam + +Unread=tag:inbox and tag:unread and not tag:spam + +Important=tag:important and not tag:archived and not tag:deleted and not tag:spam + +_sent=tag:sent and not tag:archived not tag:deleted + +_spam=tag:spam |
