From 4242a01983eb57ac44d5fcfbda75339d486ea4f1 Mon Sep 17 00:00:00 2001 From: Akshay Nair Date: Tue, 27 May 2025 11:13:06 +0530 Subject: Refactor email setup + add email sender to notification --- modules/email.home/.gitignore | 1 + modules/email.home/aerc-binds.conf | 146 +++++++++++++++++++++++++++++ modules/email.home/aerc.conf | 26 +++++ modules/email.home/aerc.theme.nix | 51 ++++++++++ modules/email.home/default.nix | 77 +++++++++++++++ modules/email.home/mailbox-sync.module.nix | 70 ++++++++++++++ modules/email.home/query-map.conf | 9 ++ modules/email/.gitignore | 1 - modules/email/aerc-binds.conf | 146 ----------------------------- modules/email/aerc.conf | 26 ----- modules/email/aerc.home.nix | 77 --------------- modules/email/aerc.theme.nix | 51 ---------- modules/email/mailbox-sync.module.nix | 70 -------------- modules/email/query-map.conf | 9 -- 14 files changed, 380 insertions(+), 380 deletions(-) create mode 100644 modules/email.home/.gitignore create mode 100644 modules/email.home/aerc-binds.conf create mode 100644 modules/email.home/aerc.conf create mode 100644 modules/email.home/aerc.theme.nix create mode 100644 modules/email.home/default.nix create mode 100644 modules/email.home/mailbox-sync.module.nix create mode 100644 modules/email.home/query-map.conf delete mode 100644 modules/email/.gitignore delete mode 100644 modules/email/aerc-binds.conf delete mode 100644 modules/email/aerc.conf delete mode 100644 modules/email/aerc.home.nix delete mode 100644 modules/email/aerc.theme.nix delete mode 100644 modules/email/mailbox-sync.module.nix delete mode 100644 modules/email/query-map.conf (limited to 'modules') diff --git a/modules/email.home/.gitignore b/modules/email.home/.gitignore new file mode 100644 index 0000000..a211cae --- /dev/null +++ b/modules/email.home/.gitignore @@ -0,0 +1 @@ +private.nix diff --git a/modules/email.home/aerc-binds.conf b/modules/email.home/aerc-binds.conf new file mode 100644 index 0000000..442c9ea --- /dev/null +++ b/modules/email.home/aerc-binds.conf @@ -0,0 +1,146 @@ + = :prev-tab + = :next-tab + = :term +? = :help keys + = :prompt 'Quit? ' quit + = :prompt 'Quit? ' quit + = :suspend + + + + +[messages] +q = :prompt 'Quit? ' quit + +a = :read +A = :unread +i = :tag +important +I = :tag -important + + = :view + +j = :next +k = :prev + = :next 50% + = :next 100% + = :prev 50% + = :prev 100% +g = :select 0 +G = :select -1 + +J = :next-folder +K = :prev-folder + +v = :mark -t + = :mark -t:next +V = :mark -v + +T = :toggle-threads +za = :fold -t + +C = :compose + +rr = :reply -a +Rr = :reply + +! = :term +| = :pipe + +/ = :search +\ = :filter +n = :next-result +N = :prev-result + = :clear + +s = :split +S = :vsplit + +[messages:folder=Drafts] + = :recall + + + + +[view] +/ = :toggle-key-passthrough/ +q = :close +o = :open +S = :save +| = :pipe +D = :delete + + = :open-link + +f = :forward +rr = :reply -a +Rr = :reply + +H = :toggle-headers + = :prev-part + = :next-part +J = :next +K = :prev + + + + +[view::passthrough] +$noinherit = true +$ex = + = :toggle-key-passthrough + + + + +[compose] +$noinherit = true +$ex = +$complete = + = :prev-field + = :next-field + = :next-field + = :prev-field + = :prev-tab + = :next-tab + = :prompt 'Quit? ' quit -f + = :attach -m ~ + = :preview + + + + +[compose::editor] +$noinherit = true +$ex = + = :prev-field + = :next-field + = :prev-tab + = :next-tab + = :prompt 'Quit? ' quit -f + = :attach -m ~ + = :preview + + + + +[compose::review] +# Inline comments are used as descriptions on the review screen +y = :send # Send +n = :abort # Abort (discard message, no confirmation) +p = :preview # Preview message +e = :edit # Edit (body and headers) +a = :attach # Add attachment +d = :detach # Remove attachment +P = :postpone # Postpone + + + + + +[terminal] +$noinherit = true +$ex = + + = :prev-tab + = :next-tab + diff --git a/modules/email.home/aerc.conf b/modules/email.home/aerc.conf new file mode 100644 index 0000000..5585d25 --- /dev/null +++ b/modules/email.home/aerc.conf @@ -0,0 +1,26 @@ +[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 +empty-subject-warning = true +no-attachment-warning = ^[^>]*attach(ed|ment) + +[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 +application/pdf=pdftotext - - + +[openers] +image/*=sxiv {} +application/pdf=zathura {} + diff --git a/modules/email.home/aerc.theme.nix b/modules/email.home/aerc.theme.nix new file mode 100644 index 0000000..f2f525d --- /dev/null +++ b/modules/email.home/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.home/default.nix b/modules/email.home/default.nix new file mode 100644 index 0000000..f10e541 --- /dev/null +++ b/modules/email.home/default.nix @@ -0,0 +1,77 @@ +{ config, ... }: +# Create private.nix with work.email, work.name +# Setup with `notmuch setup` +# Authenticate with `take ~/mail/account.gmail/ && gmi init ` +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/10"; + 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; + }; + + xdg.desktopEntries.aerc-window = { + name = "aerc"; + exec = "sensible-terminal -e aerc %u"; + terminal = false; + mimeType = ["x-scheme-handler/mailto"]; + genericName = "Mail Client"; + comment = "Launches the aerc email client"; + categories = ["Office" "Network" "Email" "ConsoleOnly"]; + type = "Application"; + icon = "utilities-terminal"; + settings = { + Keywords = "Email;Mail;IMAP;SMTP"; + Version = "1.0"; + }; + }; +} diff --git a/modules/email.home/mailbox-sync.module.nix b/modules/email.home/mailbox-sync.module.nix new file mode 100644 index 0000000..bb7ee9d --- /dev/null +++ b/modules/email.home/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 + "\n" + .authors + "\n(tag: " + (.tags | join(" ")) + ")") | join("\n\n")'); + + # Notify + ${notify-send} --app-name=notmuch "Read your mail dumbass ($new_mail_count)" "\n$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.home/query-map.conf b/modules/email.home/query-map.conf new file mode 100644 index 0000000..fe14b08 --- /dev/null +++ b/modules/email.home/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 diff --git a/modules/email/.gitignore b/modules/email/.gitignore deleted file mode 100644 index a211cae..0000000 --- a/modules/email/.gitignore +++ /dev/null @@ -1 +0,0 @@ -private.nix diff --git a/modules/email/aerc-binds.conf b/modules/email/aerc-binds.conf deleted file mode 100644 index 442c9ea..0000000 --- a/modules/email/aerc-binds.conf +++ /dev/null @@ -1,146 +0,0 @@ - = :prev-tab - = :next-tab - = :term -? = :help keys - = :prompt 'Quit? ' quit - = :prompt 'Quit? ' quit - = :suspend - - - - -[messages] -q = :prompt 'Quit? ' quit - -a = :read -A = :unread -i = :tag +important -I = :tag -important - - = :view - -j = :next -k = :prev - = :next 50% - = :next 100% - = :prev 50% - = :prev 100% -g = :select 0 -G = :select -1 - -J = :next-folder -K = :prev-folder - -v = :mark -t - = :mark -t:next -V = :mark -v - -T = :toggle-threads -za = :fold -t - -C = :compose - -rr = :reply -a -Rr = :reply - -! = :term -| = :pipe - -/ = :search -\ = :filter -n = :next-result -N = :prev-result - = :clear - -s = :split -S = :vsplit - -[messages:folder=Drafts] - = :recall - - - - -[view] -/ = :toggle-key-passthrough/ -q = :close -o = :open -S = :save -| = :pipe -D = :delete - - = :open-link - -f = :forward -rr = :reply -a -Rr = :reply - -H = :toggle-headers - = :prev-part - = :next-part -J = :next -K = :prev - - - - -[view::passthrough] -$noinherit = true -$ex = - = :toggle-key-passthrough - - - - -[compose] -$noinherit = true -$ex = -$complete = - = :prev-field - = :next-field - = :next-field - = :prev-field - = :prev-tab - = :next-tab - = :prompt 'Quit? ' quit -f - = :attach -m ~ - = :preview - - - - -[compose::editor] -$noinherit = true -$ex = - = :prev-field - = :next-field - = :prev-tab - = :next-tab - = :prompt 'Quit? ' quit -f - = :attach -m ~ - = :preview - - - - -[compose::review] -# Inline comments are used as descriptions on the review screen -y = :send # Send -n = :abort # Abort (discard message, no confirmation) -p = :preview # Preview message -e = :edit # Edit (body and headers) -a = :attach # Add attachment -d = :detach # Remove attachment -P = :postpone # Postpone - - - - - -[terminal] -$noinherit = true -$ex = - - = :prev-tab - = :next-tab - diff --git a/modules/email/aerc.conf b/modules/email/aerc.conf deleted file mode 100644 index 5585d25..0000000 --- a/modules/email/aerc.conf +++ /dev/null @@ -1,26 +0,0 @@ -[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 -empty-subject-warning = true -no-attachment-warning = ^[^>]*attach(ed|ment) - -[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 -application/pdf=pdftotext - - - -[openers] -image/*=sxiv {} -application/pdf=zathura {} - diff --git a/modules/email/aerc.home.nix b/modules/email/aerc.home.nix deleted file mode 100644 index 1ba4f7d..0000000 --- a/modules/email/aerc.home.nix +++ /dev/null @@ -1,77 +0,0 @@ -{ config, ... }: -# Create private.nix with work.email, work.name -# Setup with `notmuch setup` -# Authenticate with `take ~/mail/account.gmail/ && gmi init ` -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; - }; - - xdg.desktopEntries.aerc-window = { - name = "aerc"; - exec = "sensible-terminal -e aerc %u"; - terminal = false; - mimeType = ["x-scheme-handler/mailto"]; - genericName = "Mail Client"; - comment = "Launches the aerc email client"; - categories = ["Office" "Network" "Email" "ConsoleOnly"]; - type = "Application"; - icon = "utilities-terminal"; - settings = { - Keywords = "Email;Mail;IMAP;SMTP"; - Version = "1.0"; - }; - }; -} diff --git a/modules/email/aerc.theme.nix b/modules/email/aerc.theme.nix deleted file mode 100644 index f2f525d..0000000 --- a/modules/email/aerc.theme.nix +++ /dev/null @@ -1,51 +0,0 @@ -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 deleted file mode 100644 index ad5f94e..0000000 --- a/modules/email/mailbox-sync.module.nix +++ /dev/null @@ -1,70 +0,0 @@ -{ 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 deleted file mode 100644 index fe14b08..0000000 --- a/modules/email/query-map.conf +++ /dev/null @@ -1,9 +0,0 @@ -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 -- cgit v1.3.1