;;; bandali-gnus.el --- bandali's Gnus setup -*- lexical-binding: t; -*- ;; Copyright (C) 2018-2025 Amin Bandali ;; Author: Amin Bandali ;; Keywords: mail, news ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; My trusty Gnus setup. ;;; Code: (defvar b/maildir (expand-file-name (convert-standard-filename "~/mail/"))) (eval-when-compile (progn (defvar nndraft-directory) (defvar gnus-read-newsrc-file) (defvar gnus-save-newsrc-file) (defvar gnus-gcc-mark-as-read) (defvar nnmail-split-abbrev-alist))) (declare-function article-make-date-line "gnus-art" (date type)) (with-eval-after-load 'gnus (setopt gnus-select-method '(nnnil "") gnus-secondary-select-methods `((nnimap "kelar" (nnimap-stream plain) (nnimap-address "127.0.0.1") (nnimap-server-port 143) (nnimap-authenticator plain) (nnimap-user "bandali@kelar.local") ;; (nnmail-expiry-wait immediate) (nnmail-expiry-target nnmail-fancy-expiry-target) (nnmail-fancy-expiry-targets (("from" ".*" "nnimap+kelar:Archive.%Y")))) (nnimap "ia" (nnimap-stream plain) (nnimap-address "127.0.0.1") (nnimap-server-port 143) (nnimap-authenticator plain) (nnimap-user "bandali@archive.local") (nnmail-expiry-wait immediate) (nnmail-expiry-target nnmail-fancy-expiry-target) (nnmail-fancy-expiry-targets (("from" ".*" "nnimap+ia:Archive.%Y")))) (nnimap "shemshak" (nnimap-stream plain) (nnimap-address "127.0.0.1") (nnimap-server-port 143) (nnimap-authenticator plain) (nnimap-user "bandali@shemshak.local")) (nnimap "debian" (nnimap-stream plain) (nnimap-address "127.0.0.1") (nnimap-server-port 143) (nnimap-authenticator plain) (nnimap-user "bandali@debian.local") ;; (nnmail-expiry-wait immediate) (nnmail-expiry-target nnmail-fancy-expiry-target) (nnmail-fancy-expiry-targets (("from" ".*" "nnimap+debian:Archive.%Y")))) (nnimap "gnu" (nnimap-stream plain) (nnimap-address "127.0.0.1") (nnimap-server-port 143) (nnimap-authenticator plain) (nnimap-user "bandali@gnu.local") (nnimap-inbox "INBOX") (nnimap-split-methods 'nnimap-split-fancy) (nnimap-split-fancy (| ;; (: gnus-registry-split-fancy-with-parent) ;; (: gnus-group-split-fancy "INBOX" t "INBOX") ;; spam ("X-Spam_action" "reject" "Junk") ;; keep debbugs emails in INBOX (list ".*<\\(.*\\)\\.debbugs\\.gnu\\.org>.*" "INBOX") ;; list moderation emails (from ".+-\\(owner\\|bounces\\)@\\(non\\)?gnu\\.org" "listmod") ;; gnu (list ".*<\\(.*\\)\\.\\(non\\)?gnu\\.org>.*" "l.\\1") ("Envelope-To" "emacsconf-donations@gnu.org" "l.emacsconf-donations") ;; board-eval (| (list ".*<.*\\.board-eval\\.fsf\\.org>.*" "l.board-eval") (from ".*@board-eval\\.fsf\\.org" "l.board-eval")) ;; fsf (list ".*<\\(.*\\)\\.fsf\\.org>.*" "l.\\1") ;; cfarm (from "cfarm-.*@lists\\.tetaneutral\\.net" "l.cfarm") ;; debian (list ".*<\\(.*\\)\\.\\(lists\\|other\\)\\.debian\\.org>.*" "l.\\1") (list ".*<\\(.*\\)\\.alioth-lists\\.debian\\.net>.*" "l.\\1") ;; gnus (list ".*<\\(.*\\)\\.gnus\\.org>.*" "l.\\1") ;; libreplanet (list ".*<\\(.*\\)\\.libreplanet\\.org>.*" "l.\\1") ;; iana (e.g. tz-announce) (list ".*<\\(.*\\)\\.iana\\.org>.*" "l.\\1") ;; mailop (list ".*<\\(.*\\)\\.mailop\\.org>.*" "l.\\1") ;; sdlu (list ".*<\\(.*\\)\\.spammers\\.dontlike\\.us>.*" "l.sdlu") ;; bitfolk (from ".*@\\(.+\\)?bitfolk\\.com>.*" "bitfolk") ;; haskell (list ".*<\\(.*\\)\\.haskell\\.org>.*" "l.\\1") ;; webmasters (from "webmasters\\(-comment\\)?@gnu\\.org" "webmasters") ;; other (list ".*atreus.freelists.org" "l.atreus") (list ".*deepspec.lists.cs.princeton.edu" "l.deepspec") (list ".*haskell-art.we.lurk.org" "l.haskell-art") (list ".*dev.lists.parabola.nu" "l.parabola-dev") ;; otherwise, leave mail in INBOX "INBOX"))) (nnimap "csc" (nnimap-stream plain) (nnimap-address "127.0.0.1") (nnimap-server-port 143) (nnimap-authenticator plain) (nnimap-user "abandali@csclub.uwaterloo.local") (nnimap-inbox "INBOX") (nnimap-split-methods 'nnimap-split-fancy) (nnimap-split-fancy (| ;; cron reports and other messages from root (from "root@\\(.*\\.\\)?csclub\\.uwaterloo\\.ca" "INBOX") ;; spam ("X-Spam-Flag" "YES" "Junk") ;; catch-all "INBOX")))) gnus-message-archive-group "nnimap+kelar:INBOX" gnus-parameters '(("l\\.fencepost-users" (to-address . "fencepost-users@gnu.org") (to-list . "fencepost-users@gnu.org") (list-identifier . "\\[Fencepost-users\\]")) ("l\\.haskell-cafe" (to-address . "haskell-cafe@haskell.org") (to-list . "haskell-cafe@haskell.org") (list-identifier . "\\[Haskell-cafe\\]"))) ;; (gnus-large-newsgroup 50) gnus-process-mark-toggle t gnus-home-directory (b/emacs.d "gnus/") gnus-directory (expand-file-name (convert-standard-filename "news/") gnus-home-directory) gnus-interactive-exit nil gnus-user-agent '(emacs gnus type)) (with-eval-after-load 'message (setopt message-directory (expand-file-name (convert-standard-filename "mail/") gnus-home-directory))) (with-eval-after-load 'nndraft (setopt nndraft-directory (expand-file-name (convert-standard-filename "drafts/") gnus-home-directory))) (with-eval-after-load 'nnimap (setq nnimap-record-commands init-file-debug)) (when (version< emacs-version "27") (with-eval-after-load 'nnmail (add-to-list 'nnmail-split-abbrev-alist '(list . "list-id\\|list-post\\|x-mailing-list\\|x-beenthere\\|x-loop") 'append))) (with-eval-after-load 'gnus-agent (setopt gnus-agent-synchronize-flags 'ask)) (with-eval-after-load 'gnus-art ; article (setopt gnus-buttonized-mime-types '("multipart/\\(signed\\|encrypted\\)") gnus-sorted-header-list '("^From:" "^X-RT-Originator" "^Newsgroups:" "^Subject:" "^Date:" "^Envelope-To:" "^Followup-To:" "^Reply-To:" "^Organization:" "^Summary:" "^Abstract:" "^Keywords:" "^To:" "^[BGF]?Cc:" "^Posted-To:" "^Mail-Copies-To:" "^Mail-Followup-To:" "^Apparently-To:" "^Resent-From:" "^User-Agent:" "^X-detected-operating-system:" "^X-Spam_action:" "^X-Spam_bar:" "^Message-ID:" ;; "^References:" "^List-Id:" "^Gnus-Warning:") gnus-visible-headers (mapconcat #'identity gnus-sorted-header-list "\\|"))) ;; `gnus-dired' (with-eval-after-load 'dired (require 'gnus-dired) (add-hook 'dired-mode-hook #'gnus-dired-mode)) (with-eval-after-load 'gnus-group (setopt gnus-permanently-visible-groups "\\(:INBOX$\\|:gnu$\\)") (add-hook 'gnus-group-mode-hook #'gnus-topic-mode) (add-hook 'gnus-group-mode-hook #'gnus-agent-mode)) (with-eval-after-load 'gnus-msg (let ((bandali "Amin Bandali%s - https://kelar.org/~bandali")) (defvar b/csc-signature (mapconcat #'identity `(,(format bandali ", MMath") "Systems Committee " "Computer Science Club of the University of Waterloo") "\n"))) (setopt gnus-gcc-mark-as-read t gnus-message-replysign t gnus-posting-styles '(("nnimap\\+kelar:.*" (address "bandali@kelar.org") ("X-Message-SMTP-Method" "smtp mail.kelar.org 587") (gcc "nnimap+kelar:INBOX")) ("nnimap\\+ia:.*" (address "bandali@archive.org") ("X-Message-SMTP-Method" "smtp mail.archive.org 587") (gcc "nnimap+ia:INBOX")) ("nnimap\\+shemshak:.*" (address "amin@shemshak.org") ("X-Message-SMTP-Method" "smtp mail.shemshak.org 587") (gcc "nnimap+shemshak:Sent")) ("nnimap\\+debian:.*" (address "bandali@debian.org") ("X-Message-SMTP-Method" "smtp mail-submit.debian.org 587") (gcc "nnimap+debian:INBOX")) ("nnimap\\+gnu:.*" (address "bandali@gnu.org") ("X-Message-SMTP-Method" "smtp fencepost.gnu.org 587") (gcc "nnimap+gnu:INBOX")) ("nnimap\\+.*:l\\.ubuntu-.*" (address "bandali@ubuntu.com") ("X-Message-SMTP-Method" "smtp mail.kelar.org 587")) ((header "list-id" ".*\\.lists.ubuntu.com") (address "bandali@ubuntu.com") ("X-Message-SMTP-Method" "smtp mail.kelar.org 587")) ("nnimap\\+csc:.*" (address "bandali@csclub.uwaterloo.ca") ("X-Message-SMTP-Method" "smtp mail.csclub.uwaterloo.ca 587") (signature b/csc-signature) (gcc "nnimap+csc:Sent")))) ;; `gnus-registry' ;; (setopt ;; gnus-registry-max-entries 2500 ;; gnus-registry-ignored-groups ;; (append gnus-registry-ignored-groups ;; '(("^nnimap:gnu\\.l" t) ("webmasters$" t)))) ;; (require 'gnus-registry) ;; (gnus-registry-initialize) (with-eval-after-load 'gnus-search (setopt gnus-search-use-parsed-queries t)) (with-eval-after-load 'gnus-start (setopt gnus-save-newsrc-file nil gnus-read-newsrc-file nil) (unless (fboundp 'gnus-notifications) (autoload #'gnus-notifications "gnus-start" nil t)) (add-hook 'gnus-after-getting-new-news-hook #'gnus-notifications)) (with-eval-after-load 'gnus-sum ; summary (setopt gnus-thread-sort-functions '(gnus-thread-sort-by-number gnus-thread-sort-by-subject gnus-thread-sort-by-date)) (with-eval-after-load 'message (setopt gnus-ignored-from-addresses message-dont-reply-to-names)) (defun b/gnus-junk-article (&optional n) (interactive "P" gnus-summary-mode) (gnus-summary-move-article n (gnus-group-prefixed-name "Junk" (gnus-find-method-for-group gnus-newsgroup-name)))) (defvar b/gnus-summary-prefix-map) (define-prefix-command 'b/gnus-summary-prefix-map) (b/keymap-set gnus-summary-mode-map "v" 'b/gnus-summary-prefix-map) (let ((m b/gnus-summary-prefix-map)) (b/keymap-set m "r r" #'gnus-summary-very-wide-reply) (b/keymap-set m "r q" #'gnus-summary-very-wide-reply-with-original) (b/keymap-set m "R r" #'gnus-summary-reply) (b/keymap-set m "R q" #'gnus-summary-reply-with-original) (b/keymap-set m "r a w" #'gnus-summary-show-raw-article) (b/keymap-set m "s" #'b/gnus-junk-article))) (with-eval-after-load 'gnus-topic (setopt ;; gnus-topic-line-format "%i[ %A: %(%{%n%}%) ]%v\n" gnus-topic-line-format "%i[ %(%{%n%}%) (%A) ]%v\n") (setq gnus-topic-topology `(("Gnus" visible nil nil) (("misc" visible nil nil)) (("csc" visible nil nil)) (("ia" visible nil nil)) (("kelar" visible nil nil)) (("shemshak" visible nil nil)) (("debian" visible nil nil)) (("gnu" visible nil nil)) ;; (("old-gnu" visible nil nil)) ))) (with-eval-after-load 'gnus-win (setopt gnus-use-full-window nil)) (with-eval-after-load 'mm-archive (add-to-list 'mm-archive-decoders '("application/gzip" nil "gunzip" "-S" ".zip" "-kd" "%f" "-r"))) (with-eval-after-load 'mm-decode (setopt ;; mm-attachment-override-types `("text/x-diff" "text/x-patch" ;; ,@mm-attachment-override-types) mm-discouraged-alternatives '("text/html" "text/richtext") mm-decrypt-option 'known mm-verify-option 'known) (add-to-list 'mm-inline-media-tests `("application/gzip" mm-archive-dissect-and-inline identity)) (add-to-list 'mm-inlined-types "application/gzip" 'append)) (with-eval-after-load 'mm-uu (when (version< "27" emacs-version) (set-face-attribute 'mm-uu-extract nil :extend t)) (when (version< emacs-version "27") (setopt mm-uu-diff-groups-regexp "."))) (with-eval-after-load 'mml (setopt mml-attach-file-at-the-end t mml-content-disposition-alist '((text (markdown . "attachment") (rtf . "attachment") (t . "inline")) (t . "attachment")))) (with-eval-after-load 'mml-sec (setopt mml-secure-openpgp-encrypt-to-self t mml-secure-openpgp-sign-with-sender t)) (with-eval-after-load 'recentf (add-to-list 'recentf-exclude b/maildir) (add-to-list 'recentf-exclude gnus-home-directory)))) (b/keymap-global-set "C-c g" #'gnus-plugged) (b/keymap-global-set "C-c G" #'gnus-unplugged) (provide 'bandali-gnus) ;;; bandali-gnus.el ends here