Skip to content

Instantly share code, notes, and snippets.

@demokritos
Last active May 6, 2021 11:56
Show Gist options
  • Save demokritos/df75dc157566bbd5c8180dcb95aa7bf2 to your computer and use it in GitHub Desktop.
Save demokritos/df75dc157566bbd5c8180dcb95aa7bf2 to your computer and use it in GitHub Desktop.
IMAP and SMTP authentication with GnomeOnlineAccounts in Emacs
(defun get-access-token-by-user (user)
(let ((objects
(dbus-get-all-managed-objects :session "org.gnome.OnlineAccounts" "/"))
thepath)
(setq thepath
(car
(seq-find
(lambda (obj)
(let ((mail-interface
(assoc "org.gnome.OnlineAccounts.Mail" obj)))
(equal user (cdr (assoc "ImapUserName" mail-interface)))))
objects)))
(if thepath
(dbus-call-method
:session
"org.gnome.OnlineAccounts"
thepath
"org.gnome.OnlineAccounts.OAuth2Based"
"GetAccessToken")
(message "get-access-token-by-user failed: %s" user)
nil)))
;; From https://github.com/ggervasio/gnus-gmail-oauth/blob/master/gnus-gmail-oauth.el
;; modified to get an access token from GnomeOnlineAccounts
(defun gnus-gmail-oauth2-imap-authenticator (user password)
"Authenticator for GMail OAuth2. Use as before-until advice for nnimap-login
See: https://developers.google.com/gmail/xoauth2_protocol"
(if (nnimap-capability "AUTH=XOAUTH2")
(let ((access-token (car (get-access-token-by-user user))))
(if (null access-token)
nil
(let (sequence challenge)
(erase-buffer)
(setq sequence (nnimap-send-command
"AUTHENTICATE XOAUTH2 %s"
(base64-encode-string
(format "user=%s\001auth=Bearer %s\001\001"
(nnimap-quote-specials user)
(nnimap-quote-specials access-token)))))
(setq challenge (nnimap-wait-for-line "^\\(.*\\)\n"))
;; on successful authentication, first line is capabilities,
;; next line is response
(if (string-match "^\\* CAPABILITY" challenge)
(let (response (nnimap-get-response sequence))
(cons t response))
;; send empty response on error
(let (response)
(erase-buffer)
(process-send-string
(get-buffer-process (current-buffer))
"\r\n")
(setq response (nnimap-get-response sequence))
(nnheader-report 'nnimap "%s"
(mapconcat (lambda (a)
(format "%s" a))
(car response) " "))
nil)))))))
(advice-add 'nnimap-login :before-until #'gnus-gmail-oauth2-imap-authenticator)
;; From https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00156.html
;; modified to get an access token from GnomeOnlineAccounts
(cl-defmethod smtpmail-try-auth-method
(process (_mech (eql xoauth2)) user password)
(let ((access-token (car (get-access-token-by-user user))))
(smtpmail-command-or-throw
process
(concat "AUTH XOAUTH2 "
(base64-encode-string
(format "user=%s\001auth=Bearer %s\001\001"
(nnimap-quote-specials user)
(nnimap-quote-specials access-token)) t))
235)))
(with-eval-after-load 'smtpmail
(add-to-list 'smtpmail-auth-supported 'xoauth2))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment