#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.