diff --git a/config/emacs/post-init.el b/config/emacs/post-init.el index a82ad88..3689bcd 100644 --- a/config/emacs/post-init.el +++ b/config/emacs/post-init.el @@ -583,8 +583,8 @@ frame if FRAME is nil, and to 1 if AMT is nil." ;; ========================= ;; Agenda variables -(setq org-directory "~/Documents/org/") ; Non-absolute paths for agenda and - ; capture templates will look here. +(setq org-directory "~/NPersonal/") ; Non-absolute paths for agenda and + ; capture templates will look here. (setq org-agenda-files '("inbox.org" "work.org")) @@ -614,8 +614,8 @@ frame if FRAME is nil, and to 1 if AMT is nil." ;;; Phase 3 variables ;; Org-roam variables -(setq org-roam-directory "~/Documents/org-roam/") -(setq org-roam-index-file "~/Documents/org-roam/index.org") +(setq org-roam-directory "~/NPersonal/roam/") +(setq org-roam-index-file "~/NPersonal/roam/index.org") ;;; Optional variables @@ -653,7 +653,13 @@ frame if FRAME is nil, and to 1 if AMT is nil." ("wm" "Work meeting" entry (file+headline "work.org" "Meetings") "** TODO %?\n%U\n%i\n%a") ("wr" "Work report" entry (file+headline "work.org" "Reports") - "** TODO %?\n%U\n%i\n%a"))) + "** TODO %?\n%U\n%i\n%a") + ;; Email capture + ("e" "Email") + ("et" "Email TODO" entry (file "inbox.org") + "* TODO %:fromname: %:subject\n%U\n%a\n\n%?") + ("ef" "Email Follow-up" entry (file "inbox.org") + "* TODO Follow up: %:subject\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\n%U\n%a\n\n%?"))) (setq org-agenda-custom-commands '(("n" "Agenda and All Todos" ((agenda) @@ -661,6 +667,120 @@ frame if FRAME is nil, and to 1 if AMT is nil." ("w" "Work" agenda "" ((org-agenda-files '("work.org"))))))) +;; ========================= +;; Email (mu4e) +;; ========================= + +(use-package mu4e + :ensure (:host github :repo "djcb/mu" + :files ("mu4e/*.el") + :pre-build (with-temp-file "mu4e/mu4e-config.el" + (insert (format "(defconst mu4e-mu-version %S)\n" + (string-trim (shell-command-to-string "mu --version | head -1 | awk '{print $2}'"))) + "(provide 'mu4e-config)\n"))) + :defer t + :commands (mu4e mu4e-compose-new) + :bind ("C-c e" . mu4e) + :config + ;; Set mu binary path (for Nix) + (setq mu4e-mu-binary (or (executable-find "mu") + "/etc/profiles/per-user/rayandrew/bin/mu")) + + ;; General settings + (setq mu4e-maildir "~/mail") + (setq mu4e-get-mail-command "~/dotfiles/bin/path-shim mbsync -a") + (setq mu4e-update-interval 180) ;; Update every 3 minutes + (setq mu4e-change-filenames-when-moving t) ;; Required for mbsync + + ;; Sending mail via msmtp + (setq sendmail-program "msmtp") + (setq send-mail-function 'sendmail-send-it) + (setq message-sendmail-f-is-evil t) + (setq message-sendmail-extra-arguments '("--read-envelope-from")) + (setq message-send-mail-function 'message-send-mail-with-sendmail) + + ;; Don't keep message buffers around + (setq message-kill-buffer-on-exit t) + + ;; Display settings + (setq mu4e-headers-date-format "%Y-%m-%d") + (setq mu4e-headers-time-format "%H:%M") + (setq mu4e-view-show-addresses t) + (setq mu4e-view-show-images t) + (setq mu4e-compose-dont-reply-to-self t) + + ;; Prefer plain text over HTML + (setq mm-discouraged-alternatives '("text/html" "text/richtext")) + + ;; GPG signing (not by default) + (setq mml-secure-openpgp-sign-with-sender t) + (setq mm-sign-option nil) ;; don't sign by default + + ;; Keybinding to sign message (in compose buffer) + (defun mu4e-compose-sign-message () + "Sign the current message with GPG." + (interactive) + (mml-secure-message-sign-pgpmime)) + + (add-hook 'mu4e-compose-mode-hook + (lambda () + (local-set-key (kbd "C-c C-s") 'mu4e-compose-sign-message))) + + ;; Keybindings: r for reply, R for reply-all + (define-key mu4e-headers-mode-map (kbd "r") 'mu4e-compose-reply) + (define-key mu4e-headers-mode-map (kbd "R") 'mu4e-compose-wide-reply) + (define-key mu4e-view-mode-map (kbd "r") 'mu4e-compose-reply) + (define-key mu4e-view-mode-map (kbd "R") 'mu4e-compose-wide-reply) + + ;; Keybinding: e for refile (archive) + (define-key mu4e-headers-mode-map (kbd "e") 'mu4e-headers-mark-for-refile) + (define-key mu4e-view-mode-map (kbd "e") 'mu4e-view-mark-for-refile) + + ;; t to mark (u to unmark is default) + (define-key mu4e-headers-mode-map (kbd "t") 'mu4e-headers-mark-for-something) + + ;; Use completing-read (works with vertico) + (setq mu4e-completing-read-function 'completing-read) + + ;; Contexts for multiple accounts + (setq mu4e-contexts + `(,(make-mu4e-context + :name "uchicago" + :match-func (lambda (msg) + (when msg + (string-prefix-p "/uchicago" (mu4e-message-field msg :maildir)))) + :vars '((user-mail-address . "rayandrew@uchicago.edu") + (user-full-name . "Ray Andrew") + (mu4e-drafts-folder . "/uchicago/Drafts") + (mu4e-sent-folder . "/uchicago/Sent") + (mu4e-trash-folder . "/uchicago/Trash") + (mu4e-refile-folder . "/uchicago/Archive") + (message-sendmail-extra-arguments . ("--read-envelope-from" "-a" "uchicago")))) + ,(make-mu4e-context + :name "personal" + :match-func (lambda (msg) + (when msg + (string-prefix-p "/personal" (mu4e-message-field msg :maildir)))) + :vars '((user-mail-address . "raydreww@gmail.com") + (user-full-name . "Ray Andrew") + (mu4e-drafts-folder . "/personal/[Gmail]/Drafts") + (mu4e-sent-folder . "/personal/[Gmail]/Sent Mail") + (mu4e-trash-folder . "/personal/[Gmail]/Trash") + (mu4e-refile-folder . "/personal/[Gmail]/All Mail") + (message-sendmail-extra-arguments . ("--read-envelope-from" "-a" "personal")))))) + + ;; Set default context + (setq mu4e-context-policy 'pick-first) + (setq mu4e-compose-context-policy 'ask-if-none) + + ;; Bookmarks + (setq mu4e-bookmarks + '((:name "Unread messages" :query "flag:unread AND NOT flag:trashed" :key ?u) + (:name "Today's messages" :query "date:today..now" :key ?t) + (:name "Last 7 days" :query "date:7d..now" :key ?w) + (:name "UChicago Inbox" :query "maildir:/uchicago/Inbox" :key ?i) + (:name "Personal Inbox" :query "maildir:/personal/Inbox" :key ?p)))) + (use-package wakatime-mode :config (global-wakatime-mode)) diff --git a/docs/mu4e.md b/docs/mu4e.md new file mode 100644 index 0000000..31cb138 --- /dev/null +++ b/docs/mu4e.md @@ -0,0 +1,97 @@ +# mu4e Configuration + +## Launch + +| Key | Action | +|-----|--------| +| `C-c e` | Open mu4e | + +## Main View + +| Key | Action | +|-----|--------| +| `U` | Update mail (run mbsync) | +| `j` | Jump to maildir | +| `s` | Search | +| `b` | Bookmarks | +| `C` | Compose new message | +| `;` | Switch context (account) | +| `q` | Quit mu4e | + +## Headers View (Message List) + +| Key | Action | +|-----|--------| +| `n` / `p` | Next / previous message | +| `RET` | View message | +| `d` | Mark for trash | +| `D` | Mark for delete | +| `t` | Mark for action (prompts) | +| `u` | Unmark | +| `m` | Move to folder | +| `e` | Refile (archive) | +| `+` / `-` | Mark / unmark flag | +| `!` | Mark as read | +| `?` | Mark as unread | +| `r` | Reply | +| `R` | Reply all | +| `F` | Forward | +| `x` | Execute marked actions | +| `u` | Unmark | +| `U` | Unmark all | +| `*` | Mark for something | +| `#` | Mark for deferred trash | +| `%` | Mark by pattern | +| `T` | Mark thread | +| `g` | Rerun search | +| `q` | Quit to main view | + +## Message View + +| Key | Action | +|-----|--------| +| `n` / `p` | Next / previous message | +| `SPC` / `DEL` | Scroll down / up | +| `r` | Reply | +| `R` | Reply all | +| `F` | Forward | +| `o` | Open attachment | +| `e` | Save attachment | +| `a` | View action (open in browser, etc.) | +| `#` | Toggle citation folding | +| `.` | Raw view | +| `h` | Toggle headers | +| `q` | Return to headers | + +## Compose + +| Key | Action | +|-----|--------| +| `C-c C-c` | Send message | +| `C-c C-k` | Kill (discard) message | +| `C-c C-d` | Save as draft | +| `C-c C-a` | Attach file | +| `C-c C-s` | GPG sign message (custom) | +| `C-c C-e` | GPG encrypt message | + +## Bookmarks (from main view, press `b`) + +| Key | Action | +|-----|--------| +| `u` | Unread messages | +| `t` | Today's messages | +| `w` | Last 7 days | +| `i` | UChicago Inbox | +| `p` | Personal Inbox | + +## Search Tips + +- `from:john` - messages from john +- `to:jane` - messages to jane +- `subject:meeting` - subject contains meeting +- `flag:unread` - unread messages +- `flag:attach` - messages with attachments +- `date:today..now` - today's messages +- `date:7d..now` - last 7 days +- `maildir:/uchicago/Inbox` - specific maildir +- `AND`, `OR`, `NOT` - boolean operators diff --git a/home/email/default.nix b/home/email/default.nix index e34d681..7bf9d78 100644 --- a/home/email/default.nix +++ b/home/email/default.nix @@ -46,7 +46,7 @@ muCmd = lib.optionalString config.custom.email.mu '' # Initialize mu if not already done if [ ! -d "${home-dir}/.cache/mu" ] && [ ! -d "${home-dir}/.mu" ]; then - ${pkgs.mu}/bin/mu init --maildir=${home-dir}/mail + ${pkgs.mu}/bin/mu init --maildir=${home-dir}/mail --my-address=rayandrew@uchicago.edu --my-address=raydreww@gmail.com fi ${pkgs.mu}/bin/mu index '';