Emacs Gnus 多SMTP账户邮件发送配置及问题解决

Emacs Gnus 多SMTP账户邮件发送配置及问题解决

Emacs Gnus 多SMTP账户邮件发送配置及问题解决

1 需求

在Emacs 上收发邮件,收邮件用IMAP 访问,发邮件用SMTP

2 环境

Linux Debian stretch Emacs 26 Gnus

3 问题及解决方法

网络上有许多文章介绍如何设置,大多数应该可以工作,但我喜欢打破沙锅问到底,找来的 配置也要看看是不是有必要。

收邮件用 nnimap 后端,可以查看 Emacs Gnus 手册。

单个SMTP账户的也好弄,可以网络搜索。

关于多账户的要说两句,大多数采用的是 MultipleSMTPAccounts 上介绍的方式,定义一个 change-smtp 的函数,并且在smtpmail-via-smtp 中调用它。

(defadvice smtpmail-via-smtp
    (before smtpmail-via-smtp-ad-change-smtp (recipient smtpmail-text-buffer ))
  "Call `change-smtp' before every `smtpmail-via-smtp'."
  (with-current-buffer smtpmail-text-buffer (change-smtp)))

(ad-activate 'smtpmail-via-smtp)

如果你的目录下有 .authinfo .authinfo.gpg .netrc 中的一个,并且有登录对应的服务器 的用户名和密码的话,发送邮件完全没有问题。否则的话可能会出现 参数个数不对 的问 题。

apply: Wrong number of arguments: #[(ad–addoit-function recipient smtpmail-text-buffer) smtpmail-text-buffer ad–addoit-function recipient nil change-smtp] 5], 4 M

原因在于上面这段代码中,在 smtpmail.el 中它的定义是这新的:

(defun smtpmail-via-smtp (recipient smtpmail-text-buffer
                    &optional ask-for-password)
)

少了这最后的可选参数为什么会发送不出去呢?可以从 smtpmail.el 中找答案。它的流程 是这样的:默认情况下直接尝试与邮件服务器建立连接,然后分析服务器的响应代码,只有 收到 530 或者 550 错误的时候才会使用 ask-for-password => t 调用 smtpmail-try-auth-methods ,向服务器发送用户名和密码。而 smtpmail-try-auth-methods 会首先去找 auth-source 变量中定义的文件,默认就是前文 提到的那几个文件,在其中查找用户名和密码,如果没有才会向用户询问。

所以针对 Emacs 26.3 (其他版本未检查),EmacsWiki 上的设置有些地方是没有必要的,比 如 smtp-accounts 中就完全没有必要写密码了,也不安全。 set-smtp 和 set-smtp-ssl 这两个函数中的如下两个变量设置完全没有必要。

(setq smtpmail-auth-credentials (list (list server port user password)) smtpmail-starttls-credentials (list (list server port key cert)))

完成设置后,可以测试一下。 Enjoy Emacs! 以下是我修改后的发送邮件的配置。

;; Available SMTP accounts. The format is type of connection - account pattern
;; in the from field - smtp server - port. The user name and password need in
;; ~/.authinfo for smtp server. This variable will be used in function chang-smtp,
;; if from address include the ACCOUNT PATTERN, then send mail through SMTP SERVER.
(defvar smtp-accounts
  '((ssl "@gmail.com" "smtp.gmail.com" 587 )))

;; Now lets configure smtpmail.el with your name and functions to send
;; mail using your smtp accounts by changing the from field
(require 'smtpmail)
(setq send-mail-function 'smtpmail-send-it
      message-send-mail-function 'smtpmail-send-it
      mail-from-style nil
      smtpmail-debug-info t
      smtpmail-debug-verb t)

(defun set-smtp (mech server port)
  "Set related SMTP variables for supplied parameters."
  (setq smtpmail-smtp-server server smtpmail-smtp-service port
        smtpmail-auth-supported (list mech)
        )
  (message "Setting SMTP server to `%s:%s'." server port))

(defun set-smtp-ssl (server port)
  "Set related SMTP and SSL variables for supplied parameters."
  (setq starttls-use-gnutls t
        ;starttls-gnutls-program "gnutls-cli"
        ;; If you set starttls-use-gnutls as t, It means use gnutls-cli but
        ;; starttls command tool. Of course ,you need install gnutls first on
        ;; your OS.
        starttls-extra-arguments nil
        smtpmail-smtp-server server
        smtpmail-smtp-service port
        )
  (message "Setting SMTP server to `%s:%s'. (SSL enabled.)" server port ))


(defun change-smtp ()
  "Change the SMTP server according to the current from line."
  (save-excursion
    (loop with from = (save-restriction
                        (message-narrow-to-headers)
                        (message-fetch-field "from"))
          for (auth-mech address . auth-spec) in smtp-accounts
          when (string-match address from) do (cond
                                               ((memq auth-mech '(cram-md5 plain login))
                                                (return (apply 'set-smtp (cons auth-mech auth-spec))))
                                               ((eql auth-mech 'ssl)
                                                (return (apply 'set-smtp-ssl auth-spec)))
                                               (t (error "Unrecognized SMTP auth. mechanism:`%s'." auth-mech))) finally (error "Cannot infer SMTP information."))))

;; The previous function will complain if you fill the from field with
;; an account not present in smtp-accounts.

(defadvice smtpmail-via-smtp
    (before smtpmail-via-smtp-ad-change-smtp (recipient smtpmail-text-buffer &optional ask_for_password))
  "Call `change-smtp' before every `smtpmail-via-smtp'."
  (with-current-buffer smtpmail-text-buffer (change-smtp)))

(ad-activate 'smtpmail-via-smtp)

;; This wraps send mail via smtp mail, to be able to send multiple
;; messages with smtpmail.

本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议 进行许可。

posted on 2019-10-18 10:36  YourTech-WuPeng  阅读(629)  评论(0编辑  收藏  举报

导航