Commit f4f1860273ea

Vincent Demeester <vincent@sbr.pm>
2026-01-13 14:30:21
feat(emacs): add mu4e imapfilter rule integration
Add vde/mu4e-imapfilter-add-rule function that allows adding imapfilter rules directly from viewing an email in mu4e. Usage: 1. View an email in mu4e 2. Run M-x vde/mu4e-imapfilter-add-rule 3. Choose rule type (from/domain/subject/header) 4. Choose category (delete/receipts/newsletters/archive) 5. Rule is appended to the appropriate file 6. Optional: commit and push the change This completes the mu4e integration phase of the imapfilter setup. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent f777f50
Changed files (1)
tools
emacs
tools/emacs/init.el
@@ -2112,6 +2112,7 @@ Add this function to the `after-save-hook'."
   (declare-function mu4e~mark-check-target "mu4e")
   (declare-function mu4e-flags-to-string "mu4e")
   (declare-function mu4e-message-field "mu4e")
+  (declare-function mu4e-message-at-point "mu4e")
   (declare-function mu4e-root-maildir "mu4e")
   (declare-function mu4e-join-paths "mu4e")
   (declare-function mu4e-create-maildir-maybe "mu4e")
@@ -2226,6 +2227,71 @@ Add this function to the `after-save-hook'."
 	       '( :name  "All Inboxes"
 		  :query "maildir:/icloud/INBOX OR maildir:/gmail/INBOX OR maildir:/redhat/INBOX"
 		  :key   ?b))
+
+  ;; imapfilter integration
+  (defun vde/mu4e-imapfilter-add-rule ()
+    "Add an imapfilter rule from the current email message.
+Prompts for rule type (from, domain, subject, header) and category
+(delete, receipts, newsletters, archive), then appends the rule to
+the appropriate file in ~/.local/share/imapfilter-rules/"
+    (interactive)
+    (unless (mu4e-message-at-point)
+      (user-error "No message at point"))
+    (let* ((msg (mu4e-message-at-point))
+           (from (mu4e-message-field msg :from))
+           (from-email (when from (plist-get (car from) :email)))
+           (subject (mu4e-message-field msg :subject))
+           (rules-dir (expand-file-name "~/.local/share/imapfilter-rules"))
+
+           ;; Prompt for rule type
+           (rule-type (completing-read "Rule type: "
+                                       '("from" "domain" "subject" "header")
+                                       nil t))
+
+           ;; Generate rule pattern based on type
+           (pattern
+            (pcase rule-type
+              ("from" from-email)
+              ("domain" (when from-email
+                          (concat "@" (replace-regexp-in-string "^.*@" "" from-email))))
+              ("subject" (read-string "Subject pattern: " subject))
+              ("header" (let ((header-name (read-string "Header name: "))
+                             (header-value (read-string "Header value: ")))
+                         (format "%s:%s" header-name header-value)))))
+
+           ;; Prompt for category
+           (category (completing-read "Category: "
+                                      '("delete" "receipts" "newsletters" "archive")
+                                      nil t))
+
+           ;; Build rule line
+           (rule-line (format "%s:%s" rule-type pattern))
+           (rule-file (expand-file-name (format "%s.txt" category) rules-dir)))
+
+      ;; Validate
+      (unless (file-directory-p rules-dir)
+        (user-error "Rules directory does not exist: %s" rules-dir))
+      (unless pattern
+        (user-error "Could not extract pattern for rule type: %s" rule-type))
+
+      ;; Show preview and confirm
+      (when (y-or-n-p (format "Add rule '%s' to %s.txt? " rule-line category))
+        ;; Append to file
+        (with-temp-buffer
+          (insert rule-line)
+          (insert "\n")
+          (append-to-file (point-min) (point-max) rule-file))
+
+        (message "Added rule: %s → %s.txt" rule-line category)
+
+        ;; Offer to commit and push
+        (when (y-or-n-p "Commit and push this rule? ")
+          (let ((default-directory rules-dir))
+            (shell-command (format "git add %s.txt" category))
+            (shell-command (format "git commit -m 'Add %s rule: %s'" category rule-line))
+            (shell-command "git push")
+            (message "Rule committed and pushed"))))))
+
   (with-eval-after-load "mm-decode"
     (add-to-list 'mm-discouraged-alternatives "text/html")
     (add-to-list 'mm-discouraged-alternatives "text/richtext")))