{ config, pkgs, lib, ... }: let mailPath = config.xdg.userDirs.extraConfig.XDG_MAIL_DIR; contactPath = config.xdg.userDirs.extraConfig.XDG_CONTACT_DIR; mail2khal = pkgs.writeShellApplication { name = "mail2khal"; runtimeInputs = with pkgs; [ khal ]; text = builtins.readFile ./config/neomutt/mail2khal.bash; }; mailsync = pkgs.writeShellApplication { name = "mailsync"; text = '' if ! ${pkgs.isync}/bin/mbsync --all then read -rsp "Press key to continue..." -n1 fi if ! ${pkgs.vdirsyncer}/bin/vdirsyncer sync then read -rsp "Press key to continue..." -n1 fi ''; }; in { accounts.email.maildirBasePath = mailPath; accounts.contact.basePath = contactPath; services.backup.paths = [ mailPath ]; # Used by 'mailsend' nnn plugin home.sessionVariables.NEOMUTT_ACCOUNTS = let profiles = builtins.attrNames config.accounts.email.accounts; in lib.concatStringsSep ";" profiles; home.packages = [ pkgs.w3m # Pretty-print HTML on the terminal pkgs.sieve-connect # Manage Sieve filters mail2khal # Convert mail to calendar events, interactively mailsync # Synchronize emails ]; programs.mbsync = { enable = true; }; programs.neomutt = { enable = true; checkStatsInterval = 60; sidebar = { enable = true; width = 35; shortPath = true; format = "%B%?F? [%F]?%* %?N?%N/?%S "; }; binds = [ { map = [ "index" "pager" ]; key = "j"; action = "next-entry"; } { map = [ "index" "pager" ]; key = "k"; action = "previous-entry"; } { map = [ "index" "pager" ]; key = "J"; action = "sidebar-next"; } { map = [ "index" "pager" ]; key = "K"; action = "sidebar-prev"; } { map = [ "index" ]; key = "g"; action = "first-entry"; } { map = [ "index" ]; key = "G"; action = "last-entry"; } { map = [ "index" "pager" ]; key = "\\Co"; action = "sidebar-open"; } { map = [ "index" "pager" ]; key = "B"; action = "sidebar-toggle-visible"; } { map = [ "index" "pager" ]; key = "r"; action = "noop"; } { map = [ "index" "pager" ]; key = "rr"; action = "reply"; } { map = [ "index" "pager" ]; key = "ra"; action = "group-reply"; } { map = [ "editor" ]; key = ""; action = "complete-query"; } { map = [ "editor" ]; key = "\\Ct"; action = "complete"; } ]; macros = [ { # Interactively define a calendar event from an email map = [ "attach" ]; key = "c"; action = "mail2khal"; } { # Add Sender and Cc email addresses to khard map = [ "index" "pager" ]; key = "a"; action = "khard add-email --headers=from,cc --skip-already-added"; } { # Save current/tagged messages to =Archive map = [ "index" ]; key = "A"; action = "=Archive"; } { # Save currently displayed message to =Archive map = [ "pager" ]; key = "A"; action = "=Archive"; } { # Save current/tagged messages to =INBOX/Follow Up map = [ "index" ]; key = "F"; action = "=INBOX/Follow Up"; } { # Save currently displayed message to =INBOX/Follow up map = [ "pager" ]; key = "F"; action = "=INBOX/Follow Up"; } { # Save current/tagged messages to =INBOX/On Hold map = [ "index" ]; key = "O"; action = "=INBOX/On Hold"; } { # Save currently displayed message to =INBOX/On Hold map = [ "pager" ]; key = "O"; action = "=INBOX/On Hold"; } ]; extraConfig = '' ## General # UTF8 support set charset = "utf-8" set attach_charset = "utf-8" set send_charset = "utf-8" # Time Neomutt will wait for user input in some blocking operations. set timeout = 300 # Avoid waiting on message display set sleep_time = 0 # Ask if the user wishes to abort sending if $abort_noattach_regex is # found in the body, but no attachments have been added. set abort_noattach = ask-yes set abort_noattach_regex = "\\<(attach(|ed|ments?)|alleg(o|ato|ati))\\>" ## Index # Group emails by thread and sort them with new emails at the bottom set sort_aux = 'last-date-received' set sort_browser = 'reverse-date' # Remove distinction between "new messages" and "old new messages" set mark_old = no # Always apply actions to all tagged entries (if any) set auto_tag = yes # Collapse thread even if it contains new messages set collapse_unread = yes # Jump to new message when thread is uncollapsed set uncollapse_jump = yes # Collapse threads by default set collapse_all = yes # Index format (`data_format` is passed to strftime and corresponds to %d # in `index_format`) set date_format="%d %b %y %T" set index_format=" %4C │ %Z │ %d │ %-30.30F (%-4.4c) │ %s" ## Pager # show context lines when going to next page set pager_context = 5 # Display mini-index to give context set pager_index_lines = 15 # Stop at the end instead of displaying next message set pager_stop = yes # Automatically display HTML in pager by using the $MAILCAPS appropriate # command marked as `copiousoutput` set implicit_auto_view # Give precedence to the HTML part of a multipart message alternative_order text/html text/enriched text/plain * # Display only a handfull of header fields ignore * unignore date sender from to cc bcc reply-to subject unignore x-mailer x-spam-status x-spam-report unignore "Content-Type:" # Pipes pretty printed message into zathura (needs `muttprint`) #set print_command="/usr/bin/muttprint --file - --penguin off\ # --topmargin 20 --bottommargin 20 --leftmargin 10 --rightmargin 10\ # --fontsize 10pt --printer - | zathura -" ## Sidebar # When abbreviating mailbox path names, use any of these characters # as path separators. set sidebar_delim_chars = '/.' # If the mailbox path is abbreviated, should it be indented? set sidebar_folder_indent = yes # Indent string for abbreviated mailboxes set sidebar_indent_string = ' ' # Sidebar divider set sidebar_divider_char = '┃' # Calculate total, new, and flagged message counts for each mailbox # right away. set mail_check_stats # Do not sort mailboxes in sidebar set sidebar_sort_method = 'unsorted' ## Writing # Always include sender's mail set include=yes # When replying to an email, use the email the message was sent to # instead of the primary one (note that the email needs to be declared # as an `alternates`). This is useful when you are using aliases. set reverse_name = yes # When forwarding a message, ask if you want to send it as a separate # message/rfc822 MIME part. This is useful when forwarding HTML emails # that otherwise get converted into plain text by neomutt and forwarded # as such. set mime_forward = ask-yes ## Misc # Postponed messages that are marked for encryption will be # self-encrypted set postpone_encrypt = yes # Attempt to decode a message before piping set pipe_decode = yes # Attempt to decode a message before printing set print_decode = yes ## Address book # Command to use when invoking 'complete-query' in 'editor' set query_command = "echo %s | xargs khard email --parsable --search-in-source-files --" ## Styling # Index color index color243 default '~A' color index color15 default '~d <1m' color index bold color05 default '~D' color index bold color243 default '~(~N)|~N' color index bold color15 default '(~(~N)|~N) ~d <1m' color index bold color03 default '~F' color status color07 color08 # Pager color attachment color243 default color hdrdefault color243 default color normal color15 color00 # Sidebar color sidebar_new bold color15 default color sidebar_highlight color15 color08 color sidebar_divider color08 default ''; }; xdg.configFile."mailcap/mailcap".text = '' text/plain; less %s; needsterminal; text/html; w3m -I %{charset} -T text/html; copiousoutput; ''; programs.khard = { enable = true; settings = { "contact table" = { display = "formatted_name"; group_by_addressbook = false; preferred_phone_number_type = [ "pref" "cell" "home" ]; preferred_email_address_type = [ "pref" "home" "work" ]; show_nicknames = true; show_uids = false; sort = "formatted_name"; }; vcard.preferred_version = "4.0"; }; }; programs.vdirsyncer.enable = true; programs.kitty.keybindings = let leader = "ctrl+space"; in { "${leader}>o>n" = "launch --type=overlay neomutt"; "${leader}>s>m" = "launch --keep-focus --location=hsplit ${mailsync}/bin/mailsync"; }; }