This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

superconfig / tools / mutt / flake-module.nix
11 kB 277 lines
1{ self, ... }: 2{ 3 perSystem = 4 { 5 pkgs, 6 lib, 7 system, 8 ... 9 }: 10 { 11 packages.mutt = 12 let 13 # Mailboxes configuration from mail.nix 14 mailboxes = self.packages.${system}.notmuch.mailboxes; 15 notmuchConfig = self.packages.${system}.notmuch.passthru.config.configFile.path; 16 17 mailcap = pkgs.writeText "mailcap" '' 18 text/html; ${pkgs.elinks}/bin/elinks -dump ; copiousoutput; 19 ''; 20 21 # Script to view HTML emails in browser with embedded images 22 viewHtmlBrowser = pkgs.writeShellScriptBin "view-html-browser" '' 23 set -euo pipefail 24 tmpfile=$(mktemp --suffix=.html) 25 trap 'rm -f "$tmpfile"' EXIT 26 27 ${pkgs.python3}/bin/python3 -c ' 28 import email, sys, base64 29 30 msg = email.message_from_file(sys.stdin) 31 32 # Build map of Content-ID -> base64 data URI 33 cid_map = {} 34 for part in msg.walk(): 35 cid = part.get("Content-ID", "").strip("<>") 36 if cid and part.get_content_maintype() == "image": 37 data = part.get_payload(decode=True) 38 if data: 39 mime = part.get_content_type() 40 cid_map[cid] = f"data:{mime};base64,{base64.b64encode(data).decode()}" 41 42 # Find HTML part 43 html = None 44 for part in msg.walk(): 45 if part.get_content_type() == "text/html": 46 payload = part.get_payload(decode=True) 47 charset = part.get_content_charset() or "utf-8" 48 html = payload.decode(charset, errors="replace") 49 break 50 51 if html: 52 for cid, data_uri in cid_map.items(): 53 html = html.replace(f"cid:{cid}", data_uri) 54 print(html) 55 else: 56 print("<html><body><p>No HTML content found.</p></body></html>") 57 ' > "$tmpfile" 58 59 ${if pkgs.stdenv.isDarwin then "open" else "xdg-open"} "$tmpfile" 60 sleep 2 61 ''; 62 63 msmtprc = pkgs.writeText "msmtprc" '' 64 defaults 65 logfile ~/.msmtp.log 66 account prism 67 host neoprism.r 68 account c-base 69 from lassulus@c-base.org 70 host c-mail.c-base.org 71 port 465 72 tls on 73 tls_starttls off 74 auth on 75 user lassulus 76 passwordeval pass show c-base/pass 77 account default: prism 78 ''; 79 80 msmtp = pkgs.writeShellScriptBin "msmtp" '' 81 export NOTMUCH_CONFIG="${notmuchConfig}" 82 83 # Check if using c-base account (either explicit -a c-base or via From: header) 84 using_cbase=0 85 for arg in "$@"; do 86 if [[ "$arg" == "c-base" ]] || [[ "$arg" =~ @c-base\.org ]]; then 87 using_cbase=1 88 break 89 fi 90 done 91 92 # For c-base account, always send directly 93 if [ "$using_cbase" -eq 1 ]; then 94 ${pkgs.coreutils}/bin/tee >(${pkgs.notmuch}/bin/notmuch insert +sent) | \ 95 ${pkgs.msmtp}/bin/msmtp -C ${msmtprc} "$@" 96 # For default account, try neoprism.r first, then SSH 97 elif ping -W2 -c1 neoprism.r >/dev/null 2>&1; then 98 ${pkgs.coreutils}/bin/tee >(${pkgs.notmuch}/bin/notmuch insert +sent) | \ 99 ${pkgs.msmtp}/bin/msmtp -C ${msmtprc} "$@" 100 else 101 # Fall back to SSH tunnel to neoprism, submit via SMTP to local daemon 102 echo "neoprism.r not reachable, sending via SSH..." >&2 103 ${pkgs.coreutils}/bin/tee >(${pkgs.notmuch}/bin/notmuch insert +sent) | \ 104 ${pkgs.openssh}/bin/ssh -p 45621 neoprism.lassul.us 'msmtp -C /dev/null --host=localhost --port=25 --read-envelope-from --read-recipients' 105 fi 106 ''; 107 108 muttrc = pkgs.writeText "muttrc" '' 109 # read html mails 110 auto_view text/html 111 set mailcap_path = ${mailcap} 112 113 # notmuch 114 set folder="$HOME/Maildir" 115 set nm_default_uri = "notmuch://$HOME/Maildir" 116 set nm_record = yes 117 set nm_record_tags = "-inbox me archive" 118 set spoolfile = +Inbox 119 set virtual_spoolfile = yes 120 121 set sendmail="${msmtp}/bin/msmtp" 122 set from="lassulus@lassul.us" 123 alternates ^.*@lassul\.us$ ^.*@.*\.r$ 124 unset envelope_from_address 125 set use_envelope_from 126 set reverse_name 127 set markers=no 128 129 set sort=threads 130 131 set index_format="%4C %Z %?GI?%GI& ? %[%y-%m-%d] %-20.20a %?M?(%3M)& ? %s %> %r %g" 132 133 virtual-mailboxes "Unread" "notmuch://?query=tag:unread" 134 virtual-mailboxes "INBOX" "notmuch://?query=tag:inbox" 135 ${lib.concatMapStringsSep "\n" ( 136 i: ''${" "}virtual-mailboxes "${i.name}" "notmuch://?query=tag:${i.name}"'' 137 ) (lib.mapAttrsToList lib.nameValuePair mailboxes)} 138 virtual-mailboxes "TODO" "notmuch://?query=tag:TODO" 139 virtual-mailboxes "Starred" "notmuch://?query=tag:*" 140 virtual-mailboxes "Archive" "notmuch://?query=tag:archive" 141 virtual-mailboxes "Sent" "notmuch://?query=tag:sent" 142 virtual-mailboxes "Junk" "notmuch://?query=tag:junk" 143 virtual-mailboxes "All" "notmuch://?query=*" 144 145 # clan.lol IMAP - no mailboxes declaration to prevent any startup connection 146 # Select the separator entry in sidebar, folder-hook will redirect to the IMAP server 147 virtual-mailboxes "clan-infra" "notmuch://?query=tag:nonexistent-separator-tag" 148 account-hook imaps://mail.clan.lol "set imap_user = 'infra@clan.lol'; set imap_pass = \"\`SOPS_AGE_KEY=\$(rbw get --folder clan.lol clan-infra --field age-key) nix develop git+https://git.clan.lol/clan/clan-infra -c clan vars get --flake git+https://git.clan.lol/clan/clan-infra web01 infra-mail/infra-password\`\"" 149 folder-hook "notmuch://\\?query=tag:nonexistent-separator-tag" "push '<change-folder>imaps://mail.clan.lol<enter>'" 150 151 tag-transforms "junk" "k" \ 152 "unread" "u" \ 153 "replied" "↻" \ 154 "TODO" "T" \ 155 156 # notmuch bindings 157 macro index \\\\ "<vfolder-from-query>" 158 macro index + "<modify-labels>+*\n<sync-mailbox>" 159 macro index - "<modify-labels>-*\n<sync-mailbox>" 160 161 # muchsync 162 bind index \Cr noop 163 macro index \Cr \ 164 "<enter-command>unset wait_key<enter> \ 165 <sync-mailbox> \ 166 <shell-escape>${self.packages.${pkgs.system}.muchsync}/bin/muchsync -vv<enter> \ 167 <sync-mailbox> 168 169 #killed 170 bind index d noop 171 bind pager d noop 172 173 bind index S noop 174 bind index s noop 175 bind pager S noop 176 bind pager s noop 177 macro index S "<modify-labels-then-hide>-inbox -unread +junk\n" 178 macro index s "<modify-labels>-junk\n" 179 macro pager S "<modify-labels-then-hide>-inbox -unread +junk\n" 180 macro pager s "<modify-labels>-junk\n" 181 182 bind index A noop 183 bind index a noop 184 bind pager A noop 185 bind pager a noop 186 macro index A "<modify-labels>+archive -unread -inbox\n" 187 macro index a "<modify-labels>-archive\n" 188 macro pager A "<modify-labels>+archive -unread -inbox\n" 189 macro pager a "<modify-labels>-archive\n" 190 191 bind index U noop 192 bind index u noop 193 bind pager U noop 194 bind pager u noop 195 macro index U "<modify-labels>+unread\n" 196 macro index u "<modify-labels>-unread\n" 197 macro pager U "<modify-labels>+unread\n" 198 macro pager u "<modify-labels>-unread\n" 199 200 bind index t noop 201 bind pager t noop 202 macro index t "<modify-labels>" 203 204 # top index bar in email view 205 set pager_index_lines=7 206 # top_index_bar toggle 207 macro pager ,@1 "<enter-command> set pager_index_lines=0; macro pager ] ,@2 'Toggle indexbar<Enter>" 208 macro pager ,@2 "<enter-command> set pager_index_lines=3; macro pager ] ,@3 'Toggle indexbar<Enter>" 209 macro pager ,@3 "<enter-command> set pager_index_lines=7; macro pager ] ,@1 'Toggle indexbar<Enter>" 210 macro pager ] ,@1 'Toggle indexbar 211 212 # scan urls from emails 213 macro index,pager \cb "<pipe-message> ${lib.getExe pkgs.urlscan}<Enter>" 214 macro attach,compose \cb "<pipe-entry> ${lib.getExe pkgs.urlscan}<Enter>" 215 216 # view HTML in graphical browser 217 macro index,pager H "<pipe-message>${viewHtmlBrowser}/bin/view-html-browser<Enter>" "View HTML in browser" 218 219 # sidebar 220 set sidebar_divider_char = '│' 221 set sidebar_delim_chars = "/" 222 set sidebar_short_path 223 set sidebar_folder_indent 224 set sidebar_visible = yes 225 set sidebar_format = '%D%?F? [%F]?%* %?N?%N/? %?S?%S?' 226 set sidebar_width = 20 227 color sidebar_new yellow red 228 229 # sidebar bindings 230 bind index <left> sidebar-prev 231 bind index <right> sidebar-next 232 bind index <space> sidebar-open 233 # sidebar toggle 234 macro index,pager ,@) "<enter-command> set sidebar_visible=no; macro index,pager [ ,@( 'Toggle sidebar'<Enter>" 235 macro index,pager ,@( "<enter-command> set sidebar_visible=yes; macro index,pager [ ,@) 'Toggle sidebar'<Enter>" 236 macro index,pager [ ,@( 'Toggle sidebar' 237 238 # forward with attachment 239 set mime_forward = no 240 set forward_attachments = yes 241 242 # better handling of long URLs 243 set wrap = 0 # don't wrap lines in the pager 244 set markers = no # don't show + markers for wrapped lines 245 set smart_wrap = yes # wrap at word boundaries when displaying 246 set pager_stop = yes # don't jump to next message at end of pager 247 ''; 248 249 in 250 (self.wrapLib.makeWrapper { 251 pkgs = pkgs; 252 package = pkgs.neomutt; 253 aliases = [ "mutt" ]; 254 runtimeInputs = [ 255 pkgs.elinks 256 pkgs.msmtp 257 pkgs.notmuch 258 pkgs.openssh 259 pkgs.urlscan 260 ] 261 ++ lib.optionals pkgs.stdenv.isLinux [ 262 pkgs.iputils 263 ]; 264 env = { 265 NOTMUCH_CONFIG = notmuchConfig; 266 }; 267 flags = { 268 "-F" = "${muttrc}"; 269 }; 270 }).overrideAttrs 271 (old: { 272 passthru = (old.passthru or { }) // { 273 inherit msmtp; 274 }; 275 }); 276 }; 277}