GnusNiftyTricks

I’ve been using Gnus for less than 24 hours… what qualifies as a nifty trick, and what is just common knowledge?

See also: EmacsNiftyTricks

Group Parameters

    ((expiry-wait . 30) 
     (expiry-target . "nnml:old.clug")
     (total-expire . t)
     (gcc-self . none)
     (to-address . "CLUG <linux@samba.org>")
     (posting-style
      (from "Damien Elmes <clug@repose.cx>")))

Basically says “move all articles older than 30 days into old.clug (from mail.clug), and don’t prompt me. Don’t add gcc headers for this group because I’ll get the response back on the list anyway. Set the to-address so that replies will only go to the list and not to the people who sent them, and change my identity so I can track spam --DamienElmes

Adaptive Scoring

AdaptiveScoring demo:

 <antifuchs> (defvar gnus-default-adaptive-score-alist
 <antifuchs>   '((gnus-unread-mark)
 <antifuchs>     (gnus-del-mark (subject -1))
 <antifuchs>     (gnus-read-mark (subject 1))
 <antifuchs>     (gnus-expirable-mark (from -1) (subject -1))
 <antifuchs>     (gnus-killed-mark (subject -3))
 <antifuchs>     (gnus-kill-file-mark)
 <antifuchs>     (gnus-ancient-mark)
 <antifuchs>     (gnus-low-score-mark)
 <antifuchs>     (gnus-catchup-mark (subject -1))))

courtesy AndreasFuchs

Tab Complete Recipients

To Add Tab completion to names in the To: field in message,

    (add-hook 'message-mode-hook
                (function (lambda() 
                           (local-set-key (kbd "<tab>") 'bbdb-complete-name)
                         )))

Use Message X

Kai has written message-x.el (http://www.uni-mainz.de/~beigs005/message-x.el) which does better for tab completion. Basically, it’s smart about whether it’s in an appropriate header or if it’s in the body. In my .gnus.el I’ve added these two lines:

    (require 'message-x)
    (setq message-x-body-function '(lambda () (interactive) (hippie-expand nil)))

That sets it to use bbdb-complete-name on a field where I might want to do name expansion or to do hippie-expand in the body. Note that it just uses the <tab> character. Using this setup it would be hard to actually insert a <tab> in the buffer. --LathI

C-q TAB should always insert a plain tab --ClausBrunzema

Gnus Harvest

If you use Kai’s excellent message-x mode, but don’t use BBDB for harvesting addresses to complete against, you can use Lisp:gnus-harvest.el, which notices e-mail address in every message or post you read or write, and collects them in an SQLite database which can be very easily and quickly queried to determine the completion list. I prefer using it with ido, to make completion as easy as possible. – JohnWiegley

  (require 'gnus-harvest)
  (gnus-harvest-install 'message-x)

No Server

    (setq gnus-read-active-file 'some)

Preserve Threads

There are some advantages to storing your replies and sent mail in the same group as the original messages. You preserve threads in personal correspondence and you can use ^ to quickly view the parent. This is how to do it in Gnus.

    (setq gnus-message-archive-method '(nnml ""))
    (setq gnus-message-archive-group
            '((lambda (x)
                (cond
                 ;; Store personal mail messages in the same group I started out in
                 ((string-match "mail.*" group) group)
                 ;; I receive a copy of all messages I send to a list, so there's no need to archive
                 ((string-match "list.*" group) nil)
                 ;; Store everything else in misc until I can sort it out
                 (t "mail.misc")))))

I use nnml for my messages and split all mailing lists off into list.* groups. Add salt and pepper to taste.

This snippet is also useful:

    (add-hook 'message-sent-hook 'gnus-score-followup-thread)

It scores up replies to my replies.

SachaChua

Correct message counts in IMAP:

:

the code you’ll find in the two sections below doesn’t apply in Gnus’ current development branch, and wouldn’t work if the IMAP server is your primary select method. My rewrite for the latest Gnus is here.

The Old Stuff (Part One)

Gnus does not support correct message counts, but imap does. Here is a little code that fetches the number of messages in an imap mbox and caches it, until the next time gnus fetches new mail.

In order to use it, put a “%ut” somewhere in your ‘gnus-group-line-format’.

(defun gnus-user-format-function-t (dummy)
  (case (car gnus-tmp-method)
    (nnimap
     (let ((count (nnimap-request-message-count gnus-tmp-qualified-group)))
       (if count
           (format "%d" count)
         "?")))
    (t
     gnus-tmp-number-total)))

(defvar nnimap-message-count-cache-alist nil)

(defun nnimap-message-count-cache-clear nil
  (setq nnimap-message-count-cache-alist nil))

(defun nnimap-message-count-cache-get (mbox &optional server)
  (when (nnimap-possibly-change-server server)
    (cadr (assoc (concat nnimap-current-server ":" mbox)
                 nnimap-message-count-cache-alist))))

(defun nnimap-message-count-cache-set (mbox count &optional server)
  (when (nnimap-possibly-change-server server)
    (push (list (concat nnimap-current-server ":" mbox)
                count) nnimap-message-count-cache-alist))
  count)



(defun nnimap-request-message-count (mbox &optional server)
  (let ((count (or (nnimap-message-count-cache-get mbox server)
                   (and (nnimap-possibly-change-server server)
                        (progn
                          (message "Requesting message count for %s..."
                                   mbox)
                          (prog1
                              (imap-mailbox-status
                               mbox 'messages nnimap-server-buffer)
                            (message "Requesting message count for %s...done"
                                     mbox)))))))
    (when count
      (nnimap-message-count-cache-set mbox count server))
    count))

(add-hook 'gnus-after-getting-new-news-hook 'nnimap-message-count-cache-clear)

Old Stuff (part deux)

I found the above very useful, thanks for it! Though, I had to modify it a bit, so it works with multiple servers and also has a new user format (%uy), which contains the correct unread count.

(defun gnus-user-format-function-t (dummy)
  (case (car gnus-tmp-method)
    (nnimap
     (message gnus-tmp-qualified-group)
     (let ((count (nnimap-request-message-count gnus-tmp-qualified-group gnus-tmp-news-server)))
       (if count
	   (format "%d" (car count))
	 "?")))
    (t
     gnus-tmp-number-total)))

(defun gnus-user-format-function-y (dummy)
  (case (car gnus-tmp-method)
    (nnimap
     (let ((count (nnimap-request-message-count gnus-tmp-qualified-group gnus-tmp-news-server)))
       (if count
	   (format "%d" (cadr count))
	 "?")))
    (t
     gnus-tmp-number-of-unread)))

(defvar nnimap-message-count-cache-alist nil)

(defun nnimap-message-count-cache-clear nil
  (setq nnimap-message-count-cache-alist nil))

(defun nnimap-message-count-cache-get (mbox &optional server)
  (when (nnimap-possibly-change-server server)
    (cadr (assoc (concat nnimap-current-server ":" mbox)
		 nnimap-message-count-cache-alist))))

(defun nnimap-message-count-cache-set (mbox count &optional server)
  (when (nnimap-possibly-change-server server)
    (push (list (concat nnimap-current-server ":" mbox)
		count) nnimap-message-count-cache-alist))
  count)

(defun nnimap-request-message-count (mbox &optional server)
  (let ((count (or (nnimap-message-count-cache-get mbox server)
		   (and (nnimap-possibly-change-server server)
			(progn
			  (message "Requesting message count for %s..."
				   mbox)
			  (prog1
			      (imap-mailbox-status
			       mbox '(messages unseen) nnimap-server-buffer)
			    (message "Requesting message count for %s...done"
				     mbox)))))))
    (when count
      (nnimap-message-count-cache-set mbox count server))
    count))

(add-hook 'gnus-after-getting-new-news-hook 'nnimap-message-count-cache-clear)

Keeping IMAP connections alive

I had problems with our IMAP server closing connections due to inactivity timeout in a way such that openssl’s s_client would not notice it. Consequently, the next command on the IMAP group would hang.

To avoid the inactivity timeout, I added a timer that periodically issues a “NOOP” IMAP command. Seems to work nicely up to now.

(setq imap-ping-interval (* 10 60))
(setq imap-ping-timer nil)

(defun imap-ping-handler ()
  ;; ping all active IMAP servers in `nnimap-server-buffer-alist'
  (when (boundp 'nnimap-server-buffer-alist)
    (let ((servers nil))
      (mapc
       (lambda (server-buffer)
         (let ((server (car server-buffer))
               (buffer (cadr server-buffer)))
           (when (and (get-buffer buffer) (not (member server servers)))
             (ignore-errors
               (with-local-quit
                 (with-temp-message
                     (format "Pinging %s..." server)
                   (imap-send-command-wait "NOOP" buffer)
                   (message "Pinging %s...done" server))))
             (setq servers (cons server servers)))))
       nnimap-server-buffer-alist)))

  (let* ((current (current-time))
	 (timer imap-ping-timer)
	 ;; compute the time when this timer will run again
	 (next-time (timer-relative-time
		     (list (aref timer 1) (aref timer 2) (aref timer 3))
		     (* 5 (aref timer 4)) 0)))
    ;; if the activation time is far in the past, skip executions
    ;; until we reach a time in the future.  This avoids a long
    ;; pause if Emacs has been suspended for hours.
    (or (> (nth 0 next-time) (nth 0 current))
	(and (= (nth 0 next-time) (nth 0 current))
	     (> (nth 1 next-time) (nth 1 current)))
	(and (= (nth 0 next-time) (nth 0 current))
	     (= (nth 1 next-time) (nth 1 current))
	     (> (nth 2 next-time) (nth 2 current)))
	(progn
	  (timer-set-time timer (timer-next-integral-multiple-of-time
				 current imap-ping-interval)
			  imap-ping-handler)
	  (timer-activate timer)))))

(setq imap-ping-timer
      (run-at-time t imap-ping-interval 'imap-ping-handler))

Emacs 24 has keepalive support built in.


CategoryGnus