Category Archives: mail

Managing my mail

I use Gnus, one of the many mail/news clients available for Emacs. The following features help me manage the volume of mail I get each day.

Mail splitting

Yes, yes, the Gmail way is to keep everything in one folder and then use searches to filter your messages. Still, I like being able to glance at my screen and see 2 personal messages and 3 planner-related messages.

Topics and group hiding

I use Gnus topics to divide my mail into folders and subfolders. Mail groups are hidden unless they have mail. Some groups like mail.misc and mail.planner are generally useful, so I keep them visible even if they don't have unread mail.

Scoring

Gnus allows you to automatically score threads and messages up and down based on various criteria. You can set it to completely hide boring messages, show them in a different color, show interesting messages in a different color, etc.

On most mailing lists and newsgroups, I don't bother reading message bodies. I just scan through subjects, hitting k to kill entire threads I don't find interesting. Gnus remembers what threads I've killed, marks them as read, and scores them down automatically. It also scores up messages containing certain keywords, replies to my posts, and threads I found interesting.

Integration with my contacts

I put interesting people in my BBDB contact database. Gnus indicates messages from them with a little + beside their name in the message summary. If someone I know is interested in a thread, I might find it interesting as well.

Hiding and article washing

I've set Gnus up to hide quoted text. This makes browsing through threads much easier because I can concentrate only on the the new parts. I can hit a few keys to expose sections of the quoted text if the replies aren't immediately obvious from the context.

I can also set it up to remove ads at the bottom of messages, particularly long signatures, To: lines with more than N recipients, that sort of thing. I can tell it to strip out HTML, too.

Displaying parent article

Sometimes I'll jump into the middle of a thread. I can use ^ to get to the parent message.

Searching

I use swish++ to index and search through my personal and planner-related mail.

Planner hyperlinks

Most of my tasks come in through e-mail. Planner lets me keep track of my TODOs easily by automatically hyperlinking to the mail message I'm looking at when I create a task. Dealing with a few items on my TODO list is much easier than going through a large inbox! =)

On Technorati: , ,

Wicked Cool Emacs: BBDB: Keeping track of contact dates

I hadn't realized just how much I missed my Big Brother Database until today. Three networking events packed into one week meant that I hadn't set aside enough time for follow up, and I felt my memories of the conversations getting a little hazy. Fortunately I'd taken some notes on my Palm, but I knew I had to get it into some kind of contact management system quickly, and Gmail Contacts just wasn't compelling enough for me. So it's back to Emacs, plain text files, and a surprisingly sophisticated contact manager.

I also promised to do some work on the book today, so everything dovetailed nicely.

The following bit of code helps me filter displayed contacts to show only the people I haven't contacted since a certain date. This is handy for remembering to keep in touch with old friends, for example. Or at least it would be handy if I used it more often and if I actually sent the letters that pile up in my e-mail drafts and my snail mail outbox... but at least it's a step in the right direction.

If you want to know who you have or haven't talked to in a while, you need to do two things. First, you need to keep track of when you talked to people. Second, you need to generate reports.

To be able to quickly add contact notes to BBDB records, add the following to your ~/.emacs:

ch6-bbdb-ping.el:

(define-key bbdb-mode-map "z" 'wicked/bbdb-ping-bbdb-record)
(defun wicked/bbdb-ping-bbdb-record (bbdb-record text &optional date regrind)
  "Adds a note for today to the current BBDB record.
Call with a prefix to specify date.
BBDB-RECORD is the record to modify (default: current).
TEXT is the note to add for DATE.
If REGRIND is non-nil, redisplay the BBDB record."
  (interactive (list (bbdb-current-record t)
                     (read-string "Notes: ")
                     ;; Reading date - more powerful with Planner, but we'll make do if necessary
                     (if (featurep 'planner)
                         (if current-prefix-arg (planner-read-date) (planner-today))
                       (if current-prefix-arg
                           (read-string "Date (YYYY.MM.DD): ")
                         (format-time-string "%Y.%m.%d")))
                     t))
  (bbdb-record-putprop bbdb-record
                       'contact
                       (concat date ": " text "\n"
                               (or (bbdb-record-getprop bbdb-record 'contact))))
  (if regrind
      (save-excursion
        (set-buffer bbdb-buffer-name)
        (bbdb-redisplay-one-record bbdb-record)))
  nil)

You can then use z in BBDB buffers to add a quick note to the "contact" field of the current record. The date is automatically noted. You can create a note for a specific date by calling {{C-u wicked/bbdb-ping-bbdb-record}} with a prefix argument. For convenience, the suggested configuration binds this to "z", because it was one of the few unbound keys I could find. Use this after you meet, call, or e-mail people, and write down a short note about the conversation you had. You might find these notes useful later on.

If you met a number of people at an event in the past and you have Planner installed and loaded, you can use {{planner-timewarp}} to set the effective date to another date. To return to today, use {{M-x planner-timewarp nil}}.

To automatically add a datestamped copy of sent e-mail subjects to people's BBDB records, add the following to your ~/.gnus:

ch6-bbdb-message-add-subject.el:

(defun wicked/message-add-subject-to-bbdb-record ()
  "Add datestamped subject note for each person this message has been sent to."
  (let* ((subject (concat (format-time-string "%Y.%m.%d")
                          ": E-mail: " (message-fetch-field "Subject") "\n"))
         (bbdb-get-addresses-headers
          (list (assoc 'recipients bbdb-get-addresses-headers)))
         records)
    (setq records
          (bbdb-update-records
           (bbdb-get-addresses nil gnus-ignored-from-addresses 'gnus-fetch-field)
           nil nil))
    (mapc (lambda (rec)
            (bbdb-record-putprop rec
                                 'contact
                                 (concat subject
                                         (or
                                          (bbdb-record-getprop rec 'contact)
                                          ""))))
          records)))
(add-hook 'message-send-hook 'wicked/message-add-subject-to-bbdb-record)

Now that you have the data, how can you use it to filter? Add the following to your ~/.emacs:

ch6-bbdb-show-only-no-contact-since.el:

(defun wicked/bbdb-show-only-no-contact-since (date &optional reverse records)
  "Show only people who haven't been pinged since DATE or at all.
If REVERSE is non-nil, show only the people you've contacted on or since DATE.
Call with a prefix argument to show only people you've contacted on or since DATE."
  (interactive (list
                (if (featurep 'planner)
                    (planner-read-date)
                  (read-string "Date (YYYY.MM.DD): "))
                current-prefix-arg (or bbdb-records (bbdb-records))))
  (let (new-records
        last-match
        timestamp
        omit
        notes)
    (while records
      ;; Find the latest date mentioned in the entry
      (let ((timestamp (wicked/bbdb-last-date
                        (if (vectorp (car records))
                            (car records)
                          (caar records)))))
        (if (if reverse
                ;; Keep if contact is >= date
                (null (string< timestamp date))
              ;; Keep if date > contact
              (string> date timestamp))
            (add-to-list 'new-records (if (vectorp (car records))
                            (car records)
                          (caar records)) t)))
      (setq records (cdr records)))
    (bbdb-display-records new-records)))

(defun wicked/bbdb-last-date (rec)
  "Return the most recent date for REC or nil if none.
Dates should be in the form YYYY.MM.DD.  The first date in the
notes field and the first date in the contact field are used, so
dates should be in reverse chronological order."
  (let* ((wicked/date-regexp
          "\\<\\([1-9][0-9][0-9][0-9]\\)\\.\\([0-9][0-9]?\\)\\.\\([0-9][0-9]?\\)\\>")
         ;; Get the first date mentioned in the notes field
         (notes-date
          (or (and (string-match wicked/date-regexp (or (bbdb-record-notes rec) ""))
                   (match-string 0 (or (bbdb-record-notes rec) "")))
              "0000.00.00"))
         ;; Get the first date mentioned in the contact field
         (contact-date
          (or (and (string-match wicked/date-regexp (or (bbdb-record-getprop rec 'contact) ""))
                   (match-string 0 (or (bbdb-record-getprop rec 'contact) "")))
              "0000.00.00")))
    ;; Compare the two dates
    (or (if (string< notes-date contact-date) contact-date notes-date)
        "0000.00.00")))

To generate a report, use {{M-x wicked/bbdb-show-only-no-contact-since}} and specify the date. These functions are much easier to use with Planner's date-handling functions. Planner can read dates like "-1" (yesterday), "-7fri" (seven Fridays ago), "2" (the second of this month), "1.2" (January 2 in this year), and "2007.01.02" (January 2, 2007).

You can also flip the filter by using the universal prefix argument ({{C-u M-x wicked/bbdb-show-only-no-contact-since}}) to show only the people you've contacted since a certain date. This is good for knowing the size of your active network. Because the filter works on displayed records, you can combine it to find all the people you talked to last year but not this year. You can also combine it with other filters to find all the people you've marked as friends, but who you haven't talked to in three months. Then you can send a personalized e-mail or make a phone list, and get back in touch. And that's how you keep track of your contact dates!

Geek: How to use offlineimap and the dovecot mail server to read your Gmail in Emacs efficiently

2015-12-24: Updated with config changes now that I'm back to using Gnus+dovecot+offlineimap+Gmail
2014-04-09: This post is from 2008. =) I think I used dovecot+offlineimap because Gnus and maildir weren't getting along properly and directly connecting with IMAP to Gmail's server was slow, but things have probably changed a fair bit since then. I eventually moved to using the Gmail web interface for most things, but I still miss my Gnus setup!
  1. Make sure you've set up Postfix or some other mail server that can send mail.
  2. Install dovecot (IMAP server) and offlineimap (IMAP synchronization). You can probably find binaries for your distribution.
  3. Edit /etc/dovecot/conf.d/10-mail.conf and set the following:
    mail_location = maildir:~/Maildir:LAYOUT=fs
  4. Use the instructions from http://unix.stackexchange.com/questions/44214/encrypt-offlineimap-password to set up GPG-encrypted passwords. (optional)
  5. Put the following in ~/.offlineimaprc, changing the details as needed.
    [general]
    accounts = SachaGmail
    pythonfile = ~/bin/offlineimap-password.py
    
    [Account SachaGmail]
    localrepository = Local
    remoterepository = Gmail
    status_backend = sqlite
    
    [Repository Local]
    type = Maildir
    localfolders = ~/Maildir
    
    [Repository Gmail]
    type = Gmail
    maxconnections = 2
    remoteuser = [email protected]
    realdelete = no
    folderfilter = lambda foldername: foldername in ['INBOX', '[Gmail]/All Mail', '[Gmail]/Sent Mail', '[Gmail].Starred', '[Gmail].Drafts', '[Gmail].Important']
    nametrans = lambda folder: re.sub('^INBOX$', '[Gmail].Inbox', folder)
    sslcacertfile = /etc/ssl/certs/ca-certificates.crt
    remotepasseval = mailpasswd("gmail")
    
    If you feel comfortable specifying your password in your ~/.offlineimaprc, you can do so by changing remotepasseval to remotepass. If so, you don't need the pythonfile line.
  6. chmod go-rwx ~/.offlineimaprc for a little bit of safety.
  7. Type offlineimap to start synchronizing.
  8. While that's synchronizing, use something like this as your ~/.gnus:
    (setq gnus-select-method
          '(nnimap "Mail"
    	       (nnimap-address "localhost")
    	       (nnimap-stream network)
    	       (nnimap-authenticator login)))
    
    (setq user-mail-address "[email protected]")
    (setq gnus-ignored-from-addresses "youruser")
    
  9. Start Emacs. Start Gnus with M-x gnus. If you don't see the INBOX group, press ^ (gnus-group-enter-server-mode), open nnimap:Mail, move your cursor to the INBOX, and either press RET to go into the group or press u (gnus-browse-unsubscribe-current-group) to toggle the subscription status until you're subscribed to the group. Then it should show up on the group screen (M-x gnus).
Hope that helps. Have fun!

Emacs Gnus: Searching Mail

There are several ways to find messages in Emacs. From the summary buffer, you can use / o (gnus-summary-insert-old-articles) to display all or some old messages. You can then scan through the headers in the summary buffer by using C-s (isearch-forward), or you can limit the displayed messages with these commands:

Messages from a given author/ agnus-summary-limit-to-author
Messages whose subjects matching a given regular expression/ /gnus-summary-limit-to-subject
Messages that match a given extra header/ xgnus-summary-limit-to-extra-headers
Messages at least N days old/ tgnus-summary-limit-to-age

Limits work on the messages that are currently displayed, so you can apply multiple limits. If you make a mistake, use / w (gnus-summary-pop-limit) to remove the previous limit. You can repeat / w (gnus-summary-pop-limit) until satisfied. To remove all the limits, type C-u / w (gnus-summary-popl-limit).

If you specify a prefix, the limit's meaning is reversed. For example, C-u / a (gnus-summary-limit-to-author) will remove the messages from the matching author or authors.

You can use Gnus to search the currently-displayed messages by using M-s (gnus-summary-search-article-forward) and M-r (gnus-summary-search-article-backward).

If you want to search a lot of mail, you'll find NNIR handy. NNIR is a front-end to mail search engines which can index your mail and return search results quickly. If you want to use NNIR with a local or remote IMAP server, you will need to use nnir.el and imap.el. If you download your mail using fetchmail or connect to a POP3 server and use an nnml backend, you can use NNIR with a search engine such as swish-e to search your ~/Mail directory efficiently.

1.6.7.1 Setting up IMAP and NNIR

If you use IMAP, then your mail is stored on the mail server and you'll need to use the IMAP search interface to search through it. Download nnir.el from http://www.emacswiki.org/cgi-bin/wiki/download/nnir.el and save it to your ~/elisp directory. You will also need an imap.el that is newer than the one that comes with Emacs 22. Download imap.el from http://www.emacswiki.org/cgi-bin/wiki/download/imap.el and save it to your ~/elisp directory as well. Because Gnus comes with an older version of imap.el, you will need to make sure that the new version of imap.el is loaded. Add the following to your ~/.gnus:

(add-to-list 'load-path "~/elisp")
(load-file "~/elisp/imap.el")
(require 'nnir)

Restart your Emacs. You can check if the correct version of imap.el has been loaded by typing M-x locate-library and specifying imap.el. If Emacs reports "~/elisp/imap.el", then Gnus is configured to use the updated imap.el.

1.6.7.2 Setting up POP3 and NNIR

If you use the configuration for POP3 that is suggested in this chapter, then your mail is stored in the nnml backend, which uses one file per message. To search this using NNIR, to install nnir.el and an external search mail engine. The Namazu search engine runs on Linux, UNIX, and Microsoft Windows, so that's what we'll talk about here. To find and configure other mail search engines supported by NNIR, check out the comments in nnir.el.

First, you'll need to download and install Namazu. If Namazu is available as a package for your distribution, install it that way, as it depends on a number of other programs. An installer for Microsoft Windows can be found at http://www.namazu.org/windows/ . If you need to build Namazu from source, you can get the source code and instructions from http://www.namazu.org .

After you've installed Namazu, create a directory for Namazu's index files, such as ~/.namazu-mail. Then index your mail by typing this at the command-line:

mknmz --mailnews -O ~/.namazu-mail ~/Mail

and add the following to your ~/.gnus:

(add-to-list 'load-path "~/elisp")
(require 'nnir)
(setq nnir-search-engine 'namazu)
(setq nnir-namazu-index-directory (expand-file-name "~/.namazu-mail"))
(setq nnir-namazu-remove-prefix (expand-file-name "~/Mail"))
(setq nnir-mail-backend gnus-select-method)
1.6.7.3 Searching your mail with NNIR

From the group buffer displayed by M-x gnus, you can type G G (gnus-group-make-nnir-group) to search your mail for a keyword.

If you're using the Namazu search engine, then you can use more sophisticated search queries such as:

Linux Emacsmessages that contain both "Linux" and "Emacs"
Linux or Emacsmessages that contain either "Linux" or "Emacs"
Emacs not Linuxmessages that contain "Emacs" but not "Linux"
Emacs and (Linux or Windows)messages that contain "Emacs" and either "Linux" or "Windows"
"apple pie"messages that contain the phrase "apple pie"
{apple pie}messages that contain the phrase "apple pie"
+from:[email protected]messages with [email protected] in the From: header
+subject:"apple pie"messages with the phrase "apple pie" in the Subject: header
+subject:apple +subject:piemessages whose Subject: headers contain both "apple" and "pie"

If matching messages are found, then you will see a temporary group with the results. Although you can't delete messages from this view, reading and replying to these messages is the same as reading and replying to regular messages.

To see a message in its original context, type G T (gnus-summary-nnir-goto-thread) from the summary buffer. This opens the message's original group. If Gnus asks you how many articles to load, press RET to accept the default of all the articles.


This is a draft for the Wicked Cool Emacs book I'm working on. =) Hope it helps!

Emacs Gnus: Organize Your Mail

People handle large volumes of mail in different ways. Keeping everything in one mailbox can quickly become unmanageable because messages you need to read get lost among messages you don't need to read.

You can move mail manually by selecting them in the summary buffer and typing B m (gnus-summary-move-article). Then type the name of the group to which you would like to move the message. The group will be created if it doesn't exist.

To move multiple messages, mark them with # (gnus-summary-mark-as-processable) and then type B m (gnus-summary-move-article). To unmark a message, type M-# (gnus-summary-unmark-as-processable). To unmark all messages, type M P U (gnus-summary-unmark-all-processable).

Automatically filing mail

Moving messages by hand is tedious and time-consuming. One way to deal with this is to set up rules that automatically file mail into different groups (or folders, as they're called in other mail clients). Gnus calls this "splitting" mail, and you can split mail on IMAP servers as well as mail downloaded from POP3 servers to your computer.

For example, if you're using Gnus to read mail from an IMAP server, you can split your messages by adding this to your ~/.gnus:

 (setq nnimap-split-inbox "INBOX") ;; (1)
 (setq nnimap-split-predicate "UNDELETED") ;; (2)
 (setq nnimap-split-rule
       '(
         ("INBOX.emacs" "^Subject:.*emacs")
         ("INBOX.work" "^To:.[email protected]")    
         ("INBOX.personal" "^To:.[email protected]")    
         ("INBOX.errors" "^From:.*\\(mailer.daemon\\|postmaster\\)")   
        )) 

If you use a different inbox, change the value of nnimap-split-inbox(1). Any messages in the inbox will be split according to nnimap-split-rule(2), which is a list where each element is a list containing the group's name and a regular expression matching the header of messages that should be filed in the group. In this example, Gnus will move mail with subjects containing the word "emacs" to INBOX.emacs, mail directed to [email protected] to the INBOX.work group, mail directed to [email protected] to the INBOX.personal group, and mail error messages to INBOX.errors. All other messages will be stored in INBOX.

If you're downloading your mail from a POP3 server and storing it in nnml, add this to your ~/.gnus instead:

 (setq nnmail-split-methods
      '(
        ("mail.emacs" "^Subject:.*emacs")
        ("mail.work" "^To:.[email protected]")    
        ("mail.personal" "^To:.[email protected]")    
        ("mail.errors" "^From:.*\\(mailer.daemon\\|postmaster\\)")   
       )) 

All other messages will be stored in mail.misc.

Start M-x gnus again, and your mail will be split into the different groups.

Where are my groups?

If you don't see your new groups in the group buffer displayed by M-x gnus, type A A (gnus-group-list-active) to see all the groups. Go to the group that you would like to add to the group buffer, then type u (gnus-group-unsubscribe-current-group) to toggle its subscription. In this example, INBOX.automated is not subscribed to, but INBOX is.

 U    13: INBOX.automated 
      76: INBOX 

When you type M-x gnus again, you'll see your subscribed groups if they have unread messages.

nnimap-split-rule and nnmail-split-methods allow you to filter interesting or uninteresting mail into different groups based on their headers. Gnus comes with an even more powerful mail splitting engine. In fact, Gnus comes with "fancy mail splitting."

Fancy mail splitting

With fancy mail splitting and some configuration, you can split mail based on a combination of criteria. You can even manually file a message and have Gnus automatically file incoming replies in the same group.

To configure an IMAP connection to use fancy mail splitting, add the following to your ~/.gnus:

 (setq nnimap-split-inbox "INBOX")
 (setq nnimap-split-predicate "UNDELETED")
 (setq nnmail-split-fancy ;; (1)
       '(|                                ;; (2)
         (: gnus-registry-split-fancy-with-parent) ;; (3)
         ;; splitting rules go here       ;; (4)
         "INBOX"                          ;; (5)
        ))
 (setq nnimap-split-rule 'nnmail-split-fancy)
 (setq nnmail-split-methods 'nnimap-split-fancy) ;; (6)
 (gnus-registry-initialize) ;; (7)

This configures IMAP to use the nnmail-split-fancy function to determine the group for messages. Note that we're setting the nnmail-split-fancy variable here. If you want to process your IMAP mail separately from your other mail, you can set the nnimap-split-fancy variable instead. If so, also set nnimap-split-rule to 'nnimap-split-fancy. Using nnmail-split-fancy here makes the other examples easier to understand, though.

The nnmail-split-fancy variable controls the splitting behavior(1). The "|" symbol means that that the first matching rule is used(2). For example, if the message being processed is a reply to a message that Gnus knows about, then the gnus-registry-split-fancy-with-parent function will return the name of the group, and nnmail-split-fancy will file the message there(3). You can add other splitting rules as well(4). If messages don't match any of these rules, the last rule specifies that the messages will be filed in INBOX(5). Set nnmail-split-methods to nnimap-split-fancy as well in order to work around some assumptions in other parts of the code(6). After that, initialize the Gnus registry(7), which is responsible for tracking moved and deleted messages. This allows you to automatically split replies into the same folders as the original messages.

To configure fancy mail splitting with an nnml backend (suggested configuration for POP3), add the following to your ~/.gnus instead:

 (gnus-registry-initialize)
 (setq nnmail-split-fancy                 
       '(|                                
         (: gnus-registry-split-fancy-with-parent)
         ;; splitting rules go here       
         "mail.misc"                          ;; (1)
        ))
 (setq nnmail-split-methods 'nnmail-split-fancy)    

This code is similar to the IMAP example, except that the default mailbox name for nnml is mail.misc(1).

Here's how the previous rules in nnmail-split-methods would be translated to nnmail-split-fancy rules for an IMAP configuration:

 (setq nnmail-split-fancy
      '(|
        (: gnus-registry-split-fancy-with-parent)
         ;; splitting rules go here       
        (from mail "INBOX.errors")   ;; (1)
        (any "[email protected]" "INBOX.work")   ;; (2)
        (any "[email protected]" "INBOX.personal") ;; 
        ("subject" "emacs" "INBOX.emacs") ;; (3)
        "INBOX"    ;; or "mail.misc" for nnml/POP3
       )) 

The from keyword matches against the "From", "Sender", and "Resent-From" fields, while the mail keyword matches common mail system addresses(1). The corresponding to keyword matches against the "To", "Cc", "Apparently-To", "Resent-To" and "Resent-Cc" headers, while any matches the fields checked by the from and to keywords(2). You can also compare against the subject and other headers(3).

You can use logic in splitting rules, too. For example, if you like reading the jokes on [email protected], but you don't like the ones sent by [email protected] (he not only has a bad sense of humor, but also likes picking on Emacs!), you can use a rule like this in your nnmail-split-fancy:

         ;; ... other splitting rules go here...
         (any "[email protected]"   ;; (1)
              (| (from "[email protected]" "INBOX.junk") ;; (2)
                 "INBOX.jokes")) ;; (3)
         ;; ... other splitting rules go here

The first rule matches all messages with "[email protected]" in from- or to-related headers. Matching messages are processed with another split rule, which moves messages from [email protected] to a separate group(2) and files the other messages in INBOX.jokes(3). To learn more about creating complex rules, read the Gnus Info manual for "Fancy Mail Splitting".

Emacs Gnus: Filter Spam

(draft for an upcoming book called Wicked Cool Emacs)

Ah, spam, the bane of our Internet lives. There is no completely reliable way to automatically filter spam. Spam messages that slip through the filters and perfectly legitimate messages that get labelled spam are all part of the occupational hazards of using the Internet.

The fastest way to filter spam is to use an external spam-filtering program such as Spamassassin or Bogofilter, so your spam can be filtered in the background and you don't have to spend time in Emacs filtering it yourself. In an ideal world, this would be done on the mail server so that you don't even need to download unwanted messages. If your inbox isn't full of ads for medicine or stocks, your mail server is probably doing a decent job of filtering the mail for you.

Server-based mail filtering

As spam filtering isn't an exact science, you'll want to find out how you can check your spam folder for misclassified mail. If you download your mail through POP, find out if there's a webmail interface that will allow you to check if any real mail has slipped into the junk mail pile. If you're on IMAP, your mail server might automatically file spam messages in a different group. Here's how to add the spam group to your list of groups:

  1. Type M-x gnus to bring up the group buffer.
  2. Type ^ (gnus-group-enter-server-mode).
  3. Choose the nnimap: entry for your mail server and press RET (gnus-server-read-server).
  4. Find the spam or junk mail group if it exists.
  5. Type u (gnus-browse-unsubscribe-current-group) to toggle the subscription. Subscribed groups will appear in your M-x gnus screen if they contain at least one unread message.

Another alternative is to have all the mail (spam and non-spam) delivered to your inbox, and then let Gnus be in charge of filing it into your spam and non-spam groups. If other people manage your mail server, ask them if you can have your mail processed by the spam filter but still delivered to your inbox. If you're administering your own mail server, set up a spam filtering system such as SpamAssassin or BogoFilter, then read the documentation of your spam filtering system to find out how to process the mail.

Spam filtering systems typically add a header such as "X-Spam-Status" or "X-Bogosity" to messages in order to indicate which messages are spam or even how spammy they are. To check if your mail server tags your messages as spam, open one of your messages in Gnus and type C-u g (gnus-summary-show-article) to view the complete headers and message. If you find a spam-related header such as X-Spam-Status, you can use it to split your mail. Add the following to your ~/.gnus:

 (setq spam-use-regex-headers t) ;; (1)
 (setq spam-regex-headers-spam "^X-Spam-Status: Yes")   ;; (2)
 (require 'spam) ;; (3)
 (spam-initialize) ;; (4)

This configures spam.el to detect spam based on message headers(1). Set spam-regex-headers-spam to a regular expression matching the header your mail server uses to indicate spam.(2) This configuration should be done before the spam.el library is loaded(3) and initialized(4), because spam.el uses the spam-use-* variables to determine which parts of the spam library to load.

In order to take advantage of this, you'll also need to add a rule that splits spam messages into a different group. If you haven't set up mail splitting yet, read qthe instructions on setting up fancy mail splitting in "Project XXX: Organize mail into groups". Add (: spam-split) to either nnmail-split-fancy or nnimap-split-fancy, depending on your configuration. For example, your ~/.gnus may look like this:

(setq nnmail-split-fancy
'(
;; ... other split rules go here ...
(: spam-split)
;; ... other split rules go here ...
"mail.misc")) ; default mailbox
(draft for an upcoming book called Wicked Cool Emacs, more to come!)