为emacs开发的收发邮件的package很多, 比如mew, wanderlust. 不过最终还是 选择了自带的gnus, 主要参考了manateelazycat的配置emacswiki:gnus speed.

因为emacs gnus是单线程程序, 所以如果网速较慢或者下载的内容较多, 打开 gnus的时候不得不等待不短的时间. 所以参考manateelazycat的做法和 emacswiki中的建议, 所有邮件和RSS订阅都利用外部程序抓好, 然后让gnus从本 地文件读取. 邮件收取和分类使用 getmailmaildrop, 发送邮件利用msmtp. 抓 取RSS XML则使用 wget.

收取邮件

getmail 和 maildrop 配置

getmailmaildrop 的配置都很简单. getmailrc 大概这样

[retriever]
type = SimplePOP3SSLRetriever
server = pop.gmail.com
username = username@gmail.com
port = 995
password = password

[destination]
type = MDA_external
path = /usr/bin/maildrop

maildrop 的默认配置文件是 ~/.mailfilter, 可以参考 courier-mta上的示例.

如果由多个邮箱可以放在不同的rcfile里, 然后使用

getmail --rcfile rcfile1 --rcfile rcfile2

来收取邮件. 如果需要使用代理可以考虑 proxychains. 然后利用 crontab 创建定时任务即可.

gnus 收取邮件

我这里的配置基本来自 manateelazycat, 做了一些简化. 如果本地的Maildir 是 “~/Mail”, 那么通过

(setq gnus-secondary-select-methods '((nnmaildir "Mail" (directory "~/Mail/"))))

把邮箱添加到gnus中. 可以按 “L” 在buffer *Group* 中显示Maildir中的所有邮 箱.

发送邮件

msmtp 的配置也很简单, archwiki:msmtp 上就有现成的示例. 唯一的问题在于似 乎无法通过 proxychains 走ss代理.

gnus里配置如下

(setq send-mail-function 'sendmail-send-it
      message-send-mail-function 'sendmail-send-it
      sendmail-program (executable-find "msmtp")
      message-sendmail-extra-arguments '("--read-envelope-from")
      mail-specify-envelope-from t
      mail-envelope-from 'header
      ;; mail-envelope-from will be automatically loaded if
      ;; sendmail.el is loaded, this is in case
      message-sendmail-envelope-from 'header
      )

其中 --read-envelope-from 是让 msmtp 自己根据header来选择发送的 邮箱, 在使用多个邮箱的时候很有帮助.

RSS 订阅

说起gnus的RSS 订阅, 上一篇 博文里还挺惭愧的, 给 nnrss 找了个不存在的 bug. 这里介绍一下离线抓取 RSS XML的一些设置. 基本想法就是通过 nnrss-generate-download-script 自动生成抓取脚本, 然后每次添加RSS源的 时候自动向脚本里添加该源抓取链接.

设置从本地读取RSS

(setq nnrss-use-local t)

默认的 nnrss-generate-download-script 会忽略掉没有新文件的源, 所以做 了一点修改

(setq my-nnrss-download-script-file "~/bin/nnrsscrawler")
(defun my-nnrss-generate-download-script ()
   "same as nnrss-generate-download-script, but read urls from `nnrss-group-alist'
 instead of `nnrss-group-data'"
   (interactive)
   (with-temp-buffer
     (progn
       (insert "#!/bin/sh\n")
       (insert "WGET=wget\n")
       (insert "RSSDIR='" (expand-file-name nnrss-directory) "'\n")
       (dolist (elem nnrss-group-alist)
 	(let ((xmlname (nnrss-translate-file-chars (concat (car elem) ".xml")))
 	      (url (nth 1 elem)))
 	  (insert "$WGET -q -O \"$RSSDIR\"/'" xmlname "' '" url "'\n")))
       (write-file my-nnrss-download-script-file)
       (shell-command (concat "chmod u+x " my-nnrss-download-script-file)))
     )
   )

最后是在订阅RSS同时把源添加到抓取脚本

(defun my-save-crawler-after-make-rss-group (original-fun &rest args)
  "save newly added group to `my-nnrss-download-script-file'"
  (let ((old-length (length nnrss-group-alist)))
    (apply original-fun args)
    (if (file-exists-p my-nnrss-download-script-file)
	;; compare old and new nnrss-group-alist to get new added rss groups
	(unless (= old-length (length nnrss-group-alist))
	  (let* ((elem (car nnrss-group-alist))
		 (xmlname (nnrss-translate-file-chars (concat (car elem) ".xml")))
		 (url (nth 1 elem))
		 (cmd-string (concat "$WGET -q -O \"$RSSDIR\"/'" xmlname "' '" url "'\n")))
	    (write-region cmd-string nil my-nnrss-download-script-file 'append)
	    )
	  )
      (my-nnrss-generate-download-script my-nnrss-download-script-file)
      )
    )
  )

(advice-add 'gnus-group-make-rss-group :around #'my-save-crawler-after-make-rss-group)

小结

折腾了emacs gnus来收发邮件和订阅RSS. 虽然还没有实现 msmtp 通过代理来 发送gmail邮件, 不过暂时告一段落吧.