#EmacsConf backstage: reviewing the last message from a speaker
| emacs, emacsconf, notmuchOne of the things I keep an eye out for when organizing EmacsConf is the most recent time we heard from a speaker. Sometimes life happens and speakers get too busy to prepare a video, so we might offer to let them do it live. Sometimes e-mail delivery issues get in the way and we don't hear from speakers because some server in between has spam filters set too strong. So I made a function that lists the most recent e-mail we got from the speaker that includes "emacsconf" in it. That was a good excuse to learn more about tabulated-list-mode.
I started by figuring out how to get all the e-mail addresses associated with a talk.
emacsconf-mail-get-all-email-addresses: Return all the possible e-mail addresses for TALK.
(defun emacsconf-mail-get-all-email-addresses (talk) "Return all the possible e-mail addresses for TALK." (split-string (downcase (string-join (seq-uniq (seq-keep (lambda (field) (plist-get talk field)) '(:email :public-email :email-alias))) ",")) " *, *"))
Then I figured out the notmuch search to use to get all messages. Some
people write a lot, so I limited it to just the ones that have
emacsconf
as well. Notmuch can return JSON, so that's easy to parse.
emacsconf-mail-notmuch-tag: Tag to use when searching the Notmuch database for mail.
(defvar emacsconf-mail-notmuch-tag "emacsconf" "Tag to use when searching the Notmuch database for mail.")
emacsconf-mail-notmuch-last-message-for-talk: Return the most recent message from the speakers for TALK.
(defun emacsconf-mail-notmuch-last-message-for-talk (talk &optional subject) "Return the most recent message from the speakers for TALK. Limit to SUBJECT if specified." (let ((message (json-parse-string (shell-command-to-string (format "notmuch search --limit=1 --format=json \"%s%s\"" (mapconcat (lambda (email) (concat "from:" (shell-quote-argument email))) (emacsconf-mail-get-all-email-addresses talk) " or ") (emacsconf-surround " and " (and emacsconf-mail-notmuch-tag (shell-quote-argument emacsconf-mail-notmuch-tag)) "" "") (emacsconf-surround " and subject:" (and subject (shell-quote-argument subject)) "" ""))) :object-type 'alist))) (cons `(email . ,(plist-get talk :email)) (when (> (length message) 0) (elt message 0)))))
Then I could display all the groups of speakers so that it's easy to check if any of the speakers haven't e-mailed us in a while.
emacsconf-mail-notmuch-show-latest-messages-from-speakers: Verify that the email addresses in GROUPS have e-mailed recently.
(defun emacsconf-mail-notmuch-show-latest-messages-from-speakers (groups &optional subject) "Verify that the email addresses in GROUPS have e-mailed recently. When called interactively, pop up a report buffer showing the e-mails and messages by date, with oldest messages on top. This minimizes the risk of mail delivery issues and radio silence." (interactive (list (emacsconf-mail-groups (seq-filter (lambda (o) (not (string= (plist-get o :status) "CANCELLED"))) (emacsconf-get-talk-info))))) (let ((results (sort (mapcar (lambda (group) (emacsconf-mail-notmuch-last-message-for-talk (cadr group) subject)) groups) (lambda (a b) (< (or (alist-get 'timestamp a) -1) (or (alist-get 'timestamp b) -1)))))) (when (called-interactively-p 'any) (with-current-buffer (get-buffer-create "*Mail report*") (let ((inhibit-read-only t)) (erase-buffer)) (tabulated-list-mode) (setq tabulated-list-entries (mapcar (lambda (row) (list (alist-get 'thread row) (vector (alist-get 'email row) (or (alist-get 'date_relative row) "") (or (alist-get 'subject row) "")))) results)) (setq tabulated-list-format [("Email" 30 t) ("Date" 10 nil) ("Subject" 30 t)]) (local-set-key (kbd "RET") #'emacsconf-mail-notmuch-visit-thread-from-summary) (tabulated-list-print) (tabulated-list-init-header) (pop-to-buffer (current-buffer)))) results))
If I press RET
on a line, I can open the most recent thread. This is
handled by the emacsconf-mail-notmuch-visit-thread-from-summary
,
which is simplified by using the thread ID as the tabulated list ID.
emacsconf-mail-notmuch-visit-thread-from-summary: Display the thread from the summary.
(defun emacsconf-mail-notmuch-visit-thread-from-summary () "Display the thread from the summary." (interactive) (let (message-buffer) (save-window-excursion (setq message-buffer (notmuch-show (tabulated-list-get-id)))) (display-buffer message-buffer t)))
We haven't heard from a few speakers in a while, so I'll probably e-mail them this weekend to double-check that I'm not getting delivery issues with my e-mails to them. If that doesn't get a reply, I might try other communication methods. If they're just busy, that's cool.
It's a lot easier to spot missing or old entries in a table than it is
to try to remember who we haven't heard from recently, so hooray for
tabulated-list-mode
!
This code is in emacsconf-mail.el.