Practical guide to use Gnus with Gmail

CREATED: 2012-10-12 一

UPDATED: 2013-09-25 Wed

Author: Chen Bin

Gnus is a great email client. It’s worth your time to learn.

Many people find Gnus hard to use. I don’t agree with them. It’s easy to use if you know the how to locate the essential 5% features and ignore the other 95%..

So here is my guide. It will help you focus on that useful 5% only. It’s practical guide, based on my own experience. No geek stuff.

Why Gnus is better

  • Need less resource for the hard disk and memory.
  • The search and filter is good.
  • It’s embedded in Emacs, no extra installation if you have Emacs
  • Support different environment. For example, if I want to see html email in Linux shell without GUI environment, Gnus is a good choice.

A quick guide

See http://www.emacswiki.org/emacs/GnusGmail on setting up Gnus for Gmail. You can also copy my Gmail setting at the end of this article.

In order to start Gnus, you need input command “M-x gnus”.

If the Gnus properly set up, you will come to the “Group Buffer” window. The “Group Buffer” lists the email folders. But in Gnus, the folder is named “Group”. By default, the groups (email folders) are invisible. You need subscribe the groups to make it visible. For example, my Gmail folder “Inbox” is a group named “nnimap+gmail:INBOX” in “Group Buffer” and it’s invisible by default!. If I don’t subscribe that group, I can’t read email in my INBOX. I know this is confusing. But this is the way of Gnus. Check my next section to see how to subscribe groups.

After subscribing the INBOX, the group INBOX could still be in visible if INBOX does not contain unread emails. That makes no sense for an email client (It does make sense for a stone age news reader)! Anyway, the solution is simple, `C-u 5 gnus-group-list-all-groups` will get desired result. I assigned hotkey “o” to it. Here is my elisp code you could paste into your .emacs. See the Gnus Manual on Listing Groups for more details.

(defun my-gnus-group-list-subscribed-groups ()
  "List all subscribed groups with or without un-read messages"
  (interactive)
  (gnus-group-list-all-groups 5)
  )
 (add-hook 'gnus-group-mode-hook
           ;; list all the subscribed groups even they contain zero un-read messages
           (lambda () (local-set-key "o" 'my-gnus-group-list-subscribed-groups ))
           )

In the “Group Buffer”, you can select a group (email folder) by pressing “RET” to check emails in that folder. But I strongly suggest pressing “C-u RET” instead because your intention could be seeing ALL the emails instead the emails filtered by “smart” Gnus.

After selecting a group and pressing “RET”, you reach the “Summary Buffer” which is, as I said before, a list of your email.

Now everything is simple, you can press “RET” to see the email and use normail Emacs hotkeys for navigation. Hotkey “q” is for quitting “Summary Buffer”.

In summary, you only need remember “Group Buffer” for mail folders and “Summary Buffer” for mails.

That’s all you need to know about Gnus. Short tutorial, eh?

Key points on using Gnus for emails

How to search emails in Gnus

“G G” to search email at server side in “Group Buffer”. You can use “#” (“M-#” to unmark)to mark the group you want to search. If you don’t mark the groups, the curent group under cursor is searched. If you put the cursor at the first line where no, all the groups are searched.

“/ /” to limit the emails by subject at “Summary Buffer”. “Limiting” is means searching mail locally.

“/ a” to limit the emails by author at “Summary Buffer”.

“/ w” to cancel the current filter.

You can apply the limits sequentially and cancel them one by one using “/ w”

BTW, I love “Limiting” in Gnus. See http://www.gnu.org/software/emacs/manual/html_mono/gnus.html#Limiting for more limiting tricks.

See http://sachachua.com/blog/2008/05/emacs-gnus-searching-mail/ for details.

Subscribe groups

I admit this part of UI is actually far from elegant.

“A A” in “Group Buffer” to list all groups on all the connected server. It may take a while. I suggest pressing “L” to avoid querying data from all the servers if possible.

After getting the list of all subscribed/unsubscribed groups, press “u” to subscribe/unsubscribe specific group.

I repeat, in order to see the emails in “INBOX” folder/group, you need MANUALLY subscribe the group “INBOX”, right here, right now!

“l” to navigate back the default view of group buffer which you may find confusing, as I mentioned before. Press “o” is much better if you uses my elisp code to show all the subscribed groups.

“g” to refresh groups list.

Reply email

“R” to reply with quoted text. “r” to reply without quoted.

“S W” (press S then press W) to reply all (It’s named “wide reply” in Emacs) with quoted text. “S w” to reply all without quoted.

Compose new email

The hot key is “a” or “m” in “Summary Buffer”.

BTW, you don’t need open Gnus to compose a mail. You can type “C-x m” anywhere in Emacs.

Attach a file

The hot key is “C-c C-a”

Download attachment

The hot key is “o”. See “Using Mime” in Emacs manual for details.

Send email

“C-c C-c”.

BTW, Emacs always use the hotkey “C-c C-c” to submit/stop something.

Refresh Summary Buffer in Gnus (check new emails)

Hot key “/ N” or command “M-x gnus-summary-insert-new-articles”

See ALL the emails in “Summary Buffer” (IMPORTANT)

“C-u RET” on the selected group (email folder) in “Group Buffer”, or “C-u M-g” in “Summary Buffer”.

That’s the most important part of this article! Gnus only display unread emails. Kind of stupid for an email client. Say my client call me to discuss his proposal in his old emails. I open my Gnus but client’s emails are invisible in “Summary Buffer” because they are marked expired by Gnus. Can I ask my client hang on for five minutes because I cannot find the emails he sent?

Check http://stackoverflow.com/questions/4982831/i-dont-want-to-expire-mail-in-gnus for the details.

Forward mail

“C-c C-f” or “M-x gnus-summary-mail-forward” in “Summary Buffer”.

BTW, you can mark several emails you want to forward (hot key is “#”) and then forward them all at once (Holger Schauer provided this tip).

Mark all emails read

Press “c” is enough. Either in summary buffer or group buffer.

My Gnus configuration (for Gmail)

The ~/.gnus.el

; -*- Lisp -*-
(require 'nnir)

;;@see http://www.emacswiki.org/emacs/GnusGmail#toc1
(setq gnus-select-method '(nntp "news.gmane.org"))

;; ask encyption password once
(setq epa-file-cache-passphrase-for-symmetric-encryption t)

(setq smtpmail-auth-credentials "~/.authinfo.gpg")

;;@see http://gnus.org/manual/gnus_397.html
(add-to-list 'gnus-secondary-select-methods
             '(nnimap "gmail"
                      (nnimap-address "imap.gmail.com")
                      (nnimap-server-port 993)
                      (nnimap-stream ssl)
                      (nnir-search-engine imap)
                      (nnimap-authinfo-file "~/.authinfo.gpg")
                      ; @see http://www.gnu.org/software/emacs/manual/html_node/gnus/Expiring-Mail.html
                      ;; press 'E' to expire email
                      (nnmail-expiry-target "nnimap+gmail:[Gmail]/Trash")
                      (nnmail-expiry-wait 90)
                      )
             )

(setq-default
  gnus-summary-line-format "%U%R%z %(%&user-date;  %-15,15f  %B%s%)\n"
  gnus-user-date-format-alist '((t . "%Y-%m-%d %H:%M"))
  gnus-summary-thread-gathering-function 'gnus-gather-threads-by-references
  gnus-sum-thread-tree-false-root ""
  gnus-sum-thread-tree-indent ""
  gnus-sum-thread-tree-leaf-with-other "-> "
  gnus-sum-thread-tree-root ""
  gnus-sum-thread-tree-single-leaf "|_ "
  gnus-sum-thread-tree-vertical "|")

(setq gnus-thread-sort-functions
      '(
        (not gnus-thread-sort-by-date)
        (not gnus-thread-sort-by-number)
        ))

; NO 'passive
(setq gnus-use-cache t)
(setq gnus-use-adaptive-scoring t)
(setq gnus-save-score t)
(add-hook 'mail-citation-hook 'sc-cite-original)
(add-hook 'message-sent-hook 'gnus-score-followup-article)
(add-hook 'message-sent-hook 'gnus-score-followup-thread)
; @see http://stackoverflow.com/questions/945419/how-dont-use-gnus-adaptive-scoring-in-some-newsgroups
(setq gnus-parameters
      '(("nnimap.*"
         (gnus-use-scoring nil))
        ))

(defvar gnus-default-adaptive-score-alist
  '((gnus-kill-file-mark (from -10))
    (gnus-unread-mark)
    (gnus-read-mark (from 10) (subject 30))
    (gnus-catchup-mark (subject -10))
    (gnus-killed-mark (from -1) (subject -30))
    (gnus-del-mark (from -2) (subject -15))
    (gnus-ticked-mark (from 10))
    (gnus-dormant-mark (from 5))))

(setq  gnus-score-find-score-files-function
       '(gnus-score-find-hierarchical gnus-score-find-bnews bbdb/gnus-score)
       )

;; BBDB: Address list
(when (file-exists-p "/usr/share/emacs/site-lisp/bbdb")
  (add-to-list 'load-path "/usr/share/emacs/site-lisp/bbdb")
  (require 'bbdb)
  (bbdb-initialize 'message 'gnus 'sendmail)
  (setq bbdb-file "~/bbdb.db")
  (add-hook 'gnus-startup-hook 'bbdb-insinuate-gnus)
  (setq bbdb/mail-auto-create-p t
        bbdb/news-auto-create-p t)
  (defvar bbdb-time-internal-format "%Y-%m-%d"
    "The internal date format.")
  ;;;###autoload
  (defun bbdb-timestamp-hook (record)
    "For use as a `bbdb-change-hook'; maintains a notes-field called `timestamp'
    for the given record which contains the time when it was last modified.  If
    there is such a field there already, it is changed, otherwise it is added."
    (bbdb-record-putprop record 'timestamp (format-time-string
                                             bbdb-time-internal-format
                                             (current-time))))
    )


(add-hook 'message-mode-hook
          '(lambda ()
             (flyspell-mode t)
             (local-set-key "<TAB>" 'bbdb-complete-name)))

;; Fetch only part of the article if we can.  I saw this in someone
;; else's .gnus
(setq gnus-read-active-file 'some)

;; Tree view for groups.  I like the organisational feel this has.
(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)

;; Threads!  I hate reading un-threaded email -- especially mailing
;; lists.  This helps a ton!
(setq gnus-summary-thread-gathering-function
      'gnus-gather-threads-by-subject)

;; Also, I prefer to see only the top level message.  If a message has
;; several replies or is part of a thread, only show the first
;; message.  'gnus-thread-ignore-subject' will ignore the subject and
;; look at 'In-Reply-To:' and 'References:' headers.
(setq gnus-thread-hide-subtree t)
(setq gnus-thread-ignore-subject t)

; Personal Information
(setq user-full-name "My Name"
      user-mail-address "username@gmail.com"
      ;message-generate-headers-first t
      )

;; Change email address for work folder.  This is one of the most
;; interesting features of Gnus.  I plan on adding custom .sigs soon
;; for different mailing lists.
;; Usage, FROM: My Name <work>
(setq gnus-posting-styles
      '((".*"
     (name "My Name"
          (address "username@gmail.com"
                   (organization "")
                   (signature-file "~/.signature")
                   ("X-Troll" "Emacs is better than Vi")
                   )))))

; You need install the ClI brower 'w3m' and Emacs plugin 'w3m'
(setq mm-text-html-renderer 'w3m)

(setq message-send-mail-function 'smtpmail-send-it
      smtpmail-starttls-credentials '(("smtp.gmail.com" 587 nil nil))
      smtpmail-auth-credentials '(("smtp.gmail.com" 587 "username@gmail.com" nil))
      smtpmail-default-smtp-server "smtp.gmail.com"
      smtpmail-smtp-server "smtp.gmail.com"
      smtpmail-smtp-service 587
      smtpmail-local-domain "homepc")
;http://www.gnu.org/software/emacs/manual/html_node/gnus/_005b9_002e2_005d.html
(setq gnus-use-correct-string-widths nil)
(gnus-compile)

The ~/.authinfo.gpg

machine imap.gmail.com login username@gmail.com password my-secret-password port 993
machine smtp.gmail.com login username@gmail.com password my-secret-password port 587

Please note .authinfo.gpg is a encrypted file. You must use Emacs to edit it. Emacs will do the encryption/descryption on this file automatically. See http://emacswiki.org/emacs/EasyPG for technical details.

Advanced tips

How to set up email “From” field for home and office

What I want to do is, if I send emails from office “From” will be my company’s email address. But in the email sent from my home pc, the “From” is my personal address.

My solution is use $HOSTNAME to detect which computer I am using.

Here is the code to be inserted into ~/.emacs:

;; (getenv "HOSTNAME") won't work because $HOSTNAME is not an env variable
;; (system-name) won't work because as Optus required, my /etc/hosts is changed
(setq my-hostname (with-temp-buffer
        (shell-command "hostname" t)
        (goto-char (point-max))
        (delete-char -1)
        (buffer-string))
      )

(defun at-office ()
  (interactive)
  (and (string= my-hostname "my-sydney-workpc")
       (not (or (string= my-hostname "homepc")
                (string= my-hostname "eee")
                ))
       )
  )
(setq user-full-name "My Name"
      user-mail-address (if (at-office) "me@mycompany.com" "me@gmail.com")
      )

Key points:

  • $HOSTNAME is not an environment variable.
  • I grab the output of cli program “hostname” instead using elisp function `(system-name)` which get wrong hostname at my office pc
  • At my office pc, (system-name) try to get the hostname from /etc/hosts which containing a line “127.0.0.1 webdev.local.mycompany.com.au my-sydney-workpc”
  • I worked on several computers which does not belong to me, so I cannot change /etc/hosts
  • You need verify your email address in “From” field at Gmail’s web interface if you are using google’s SMTP server

2 thoughts on “Practical guide to use Gnus with Gmail

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>