mu4e: updates for core changes

Deal with (name . email) --> (:name "boo" :email "boo@example.com")
Add support for the new "changed" field.
This commit is contained in:
Dirk-Jan C. Binnema 2022-05-05 01:32:46 +03:00
parent 4b56b8779d
commit 45aec819f6
9 changed files with 187 additions and 153 deletions

View File

@ -859,8 +859,8 @@ buffer buried."
(when other-headers
(dolist (h other-headers other-headers)
(if (symbolp (car h)) (setcar h (symbol-name (car h))))
(message-add-header (concat (capitalize (car h)) ": " (cdr h) "\n" ))
))
(message-add-header
(concat (capitalize (car h)) ": " (cdr h) "\n" ))))
;; yank message
(if (bufferp yank-action)

View File

@ -1,6 +1,6 @@
;;; mu4e-contacts.el -- part of mu4e -*- lexical-binding: t -*-
;; Copyright (C) 2021 Dirk-Jan C. Binnema
;; Copyright (C) 2022 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
@ -44,14 +44,14 @@ These addresses are the ones specified with `mu init'."
:type 'boolean
:group 'mu4e-compose)
(defcustom mu4e-compose-complete-only-after "2014-01-01"
(defcustom mu4e-compose-complete-only-after "2018-01-01"
"Consider only contacts last seen after this date.
Date must be a string of the form YYY-MM-DD.
Date must be a string of the form YYYY-MM-DD.
This is useful for limiting a potentially enormous set of
contacts for auto-completion to just those that are present in
the e-mail corpus in recent timses. Set to nil to not have any
the e-mail corpus in recent times. Set to nil to not have any
time-based restriction."
:type 'string
:group 'mu4e-compose)
@ -155,6 +155,73 @@ addresses and /regular expressions/."
"determined by server; see `mu4e-personal-addresses'."
"1.3.8")
;; Helpers
;;; RFC2822 handling of phrases in mail-addresses
;;
;; The optional display-name contains a phrase, it sits before the
;; angle-addr as specified in RFC2822 for email-addresses in header
;; fields. Contributed by jhelberg.
(defun mu4e--rfc822-phrase-type (ph)
"Return an atom or quoted-string for the phrase PH.
This checks for empty string first. Then quotes around the phrase
\(returning 'rfc822-quoted-string). Then whether there is a quote
inside the phrase (returning 'rfc822-containing-quote). The
reverse of the RFC atext definition is then tested. If it
matches, nil is returned, if not, it is an 'rfc822-atom, which is
returned."
(cond
((= (length ph) 0) 'rfc822-empty)
((= (aref ph 0) ?\")
(if (string-match "\"\\([^\"\\\n]\\|\\\\.\\|\\\\\n\\)*\"" ph)
'rfc822-quoted-string
'rfc822-containing-quote)) ; starts with quote, but doesn't end with one
((string-match-p "[\"]" ph) 'rfc822-containing-quote)
((string-match-p "[\000-\037()\*<>@,;:\\\.]+" ph) nil)
(t 'rfc822-atom)))
(defun mu4e--rfc822-quote-phrase (ph)
"Quote an RFC822 phrase PH only if necessary.
Atoms and quoted strings don't need quotes. The rest do. In
case a phrase contains a quote, it will be escaped."
(let ((type (mu4e--rfc822-phrase-type ph)))
(cond
((eq type 'rfc822-atom) ph)
((eq type 'rfc822-quoted-string) ph)
((eq type 'rfc822-containing-quote)
(format "\"%s\""
(replace-regexp-in-string "\"" "\\\\\"" ph)))
(t (format "\"%s\"" ph)))))
(defsubst mu4e-contact-name (contact)
"Get the name of this CONTACT, or nil."
(plist-get contact :name))
(defsubst mu4e-contact-email (contact)
"Get the name of this CONTACT, or nil."
(plist-get contact :email))
(defsubst mu4e-contact-cons (contact)
"Convert a CONTACT plist into a old-style (name . email)."
(cons
(mu4e-contact-name contact)
(mu4e-contact-email contact)))
(defsubst mu4e-contact-make (name email)
"Creata contact plist from NAME and EMAIL."
`(:name ,name :email ,email))
(defun mu4e-contact-full (contact)
"Get the full combination of name and email address from CONTACT."
(let* ((email (mu4e-contact-email contact))
(name (mu4e-contact-name contact)))
(if (and name (> (length name) 0))
(format "%s <%s>" (mu4e--rfc822-quote-phrase name) email)
email)))
(defun mu4e--update-contacts (contacts &optional tstamp)
"Receive a sorted list of CONTACTS newer than TSTAMP.
@ -212,7 +279,7 @@ For testing/debugging."
(setq contacts (sort contacts
(lambda(cell1 cell2) (< (car cell1) (car cell2)))))
(dolist (contact contacts)
(insert (format "%s\n" (cdr contact))))))
(insert (format "%s\n" (mu4e-contact-email contact))))))
(pop-to-buffer "*mu4e-contacts-info*")))

View File

@ -1,6 +1,6 @@
;;; mu4e-draft.el -- part of mu4e, the mu mail user agent for emacs -*- lexical-binding: t -*-
;;
;; Copyright (C) 2011-2020 Dirk-Jan C. Binnema
;; Copyright (C) 2011-2022 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
@ -312,7 +312,6 @@ one. Code borrowed from `message-shorten-1'."
(nthcdr (+ (- cut 2) surplus 1) list)))
(defun mu4e~fontify-signature ()
"Give the message signatures a distinctive color. This is used
in the view and compose modes and will color each signature in
@ -360,13 +359,7 @@ This is specified as a comma-separated list of e-mail addresses.
If LST is nil, returns nil."
(when lst
(mapconcat
(lambda (addrcell)
(let ((name (car addrcell))
(email (cdr addrcell)))
(if name
(format "%s <%s>" (mu4e~rfc822-quoteit name) email)
(format "%s" email))))
lst ", ")))
(lambda (contact) (mu4e-contact-full contact)) lst ", ")))
(defun mu4e~draft-address-cell-equal (cell1 cell2)
"Return t if CELL1 and CELL2 have the same e-mail address.
@ -374,8 +367,8 @@ The comparison is done case-insensitively. If the cells done
match return nil. CELL1 and CELL2 are cons cells of the
form (NAME . EMAIL)."
(string=
(downcase (or (cdr cell1) ""))
(downcase (or (cdr cell2) ""))))
(downcase (or (mu4e-contact-email cell1) ""))
(downcase (or (mu4e-contact-email cell2) ""))))
(defun mu4e~draft-create-to-lst (origmsg)
@ -391,7 +384,7 @@ of the original, we simple copy the list form the original."
(if mu4e-compose-dont-reply-to-self
(cl-delete-if
(lambda (to-cell)
(mu4e-personal-address-p (cdr to-cell)))
(mu4e-personal-address-p (mu4e-contact-email to-cell)))
reply-to)
reply-to)))
@ -406,7 +399,7 @@ I.e. return all the addresses in ADDRS not matching
((functionp mu4e-compose-reply-ignore-address)
(cl-remove-if
(lambda (elt)
(funcall mu4e-compose-reply-ignore-address (cdr elt)))
(funcall mu4e-compose-reply-ignore-address (mu4e-contact-email elt)))
addrs))
(t
;; regexp or list of regexps
@ -417,7 +410,7 @@ I.e. return all the addresses in ADDRS not matching
regexp)))
(cl-remove-if
(lambda (elt)
(string-match regexp (cdr elt)))
(string-match regexp (mu4e-contact-email elt)))
addrs)))))
(defun mu4e~draft-create-cc-lst (origmsg &optional reply-all include-from)
@ -452,7 +445,7 @@ REPLY-ALL."
cc-lst
(cl-delete-if
(lambda (cc-cell)
(mu4e-personal-address-p (cdr cc-cell)))
(mu4e-personal-address-p (mu4e-contact-email cc-cell)))
cc-lst))))
cc-lst)))
@ -470,53 +463,14 @@ message. Return nil if there are no recipients for the particular field."
(otherwise
(mu4e-error "Unsupported field")))))
;;; RFC2822 handling of phrases in mail-addresses
;;
;; The optional display-name contains a phrase, it sits before the
;; angle-addr as specified in RFC2822 for email-addresses in header
;; fields. Contributed by jhelberg.
(defun mu4e~rfc822-phrase-type (ph)
"Return an atom or quoted-string for the phrase PH.
This checks for empty string first. Then quotes around the phrase
\(returning 'rfc822-quoted-string). Then whether there is a quote
inside the phrase (returning 'rfc822-containing-quote).
The reverse of the RFC atext definition is then tested.
If it matches, nil is returned, if not, it is an 'rfc822-atom, which
is returned."
(cond
((= (length ph) 0) 'rfc822-empty)
((= (aref ph 0) ?\")
(if (string-match "\"\\([^\"\\\n]\\|\\\\.\\|\\\\\n\\)*\"" ph)
'rfc822-quoted-string
'rfc822-containing-quote)) ; starts with quote, but doesn't end with one
((string-match-p "[\"]" ph) 'rfc822-containing-quote)
((string-match-p "[\000-\037()\*<>@,;:\\\.]+" ph) nil)
(t 'rfc822-atom)))
(defun mu4e~rfc822-quoteit (ph)
"Quote an RFC822 phrase PH only if necessary.
Atoms and quoted strings don't need quotes. The rest do. In
case a phrase contains a quote, it will be escaped."
(let ((type (mu4e~rfc822-phrase-type ph)))
(cond
((eq type 'rfc822-atom) ph)
((eq type 'rfc822-quoted-string) ph)
((eq type 'rfc822-containing-quote)
(format "\"%s\""
(replace-regexp-in-string "\"" "\\\\\"" ph)))
(t (format "\"%s\"" ph)))))
(defun mu4e~draft-from-construct ()
"Construct a value for the From:-field of the reply.
This is based on the variable `user-full-name' and
`user-mail-address'; if the latter is nil, function returns nil."
(when user-mail-address
(if user-full-name
(format "%s <%s>" (mu4e~rfc822-quoteit user-full-name) user-mail-address)
(format "%s" user-mail-address))))
(mu4e-contact-full (mu4e-contact-make
user-full-name
user-mail-address))))
;;; Header separators
@ -527,34 +481,34 @@ the body starts. Note, in `mu4e-compose-mode', we use
`before-save-hook' and `after-save-hook' to ensure that this
separator is never written to the message file. Also see
`mu4e-remove-mail-header-separator'."
;; we set this here explicitly, since (as it has happened) a wrong
;; value for this (such as "") breaks address completion and other things
(set (make-local-variable 'mail-header-separator) "--text follows this line--")
(put 'mail-header-separator 'permanent-local t)
(save-excursion
;; make sure there's not one already
(mu4e~draft-remove-mail-header-separator)
(let ((sepa (propertize mail-header-separator
'intangible t
;; don't make this read-only, message-mode
;; seems to require it being writable in some cases
;;'read-only "Can't touch this"
'rear-nonsticky t
'font-lock-face 'mu4e-compose-separator-face)))
(widen)
;; search for the first empty line
(goto-char (point-min))
(if (search-forward-regexp "^$" nil t)
(progn
(replace-match sepa)
;; `message-narrow-to-headers` searches for a
;; `mail-header-separator` followed by a new line. Therefore, we
;; must insert a newline if on the last line of the buffer.
(when (= (point) (point-max))
(insert "\n")))
(progn ;; no empty line? then prepend one
(goto-char (point-max))
(insert "\n" sepa))))))
;; we set this here explicitly, since (as it has happened) a wrong
;; value for this (such as "") breaks address completion and other things
(set (make-local-variable 'mail-header-separator) "--text follows this line--")
(put 'mail-header-separator 'permanent-local t)
(save-excursion
;; make sure there's not one already
(mu4e~draft-remove-mail-header-separator)
(let ((sepa (propertize mail-header-separator
'intangible t
;; don't make this read-only, message-mode
;; seems to require it being writable in some cases
;;'read-only "Can't touch this"
'rear-nonsticky t
'font-lock-face 'mu4e-compose-separator-face)))
(widen)
;; search for the first empty line
(goto-char (point-min))
(if (search-forward-regexp "^$" nil t)
(progn
(replace-match sepa)
;; `message-narrow-to-headers` searches for a
;; `mail-header-separator` followed by a new line. Therefore, we
;; must insert a newline if on the last line of the buffer.
(when (= (point) (point-max))
(insert "\n")))
(progn ;; no empty line? then prepend one
(goto-char (point-max))
(insert "\n" sepa))))))
(defun mu4e~draft-remove-mail-header-separator ()
"Remove `mail-header-separator'.

View File

@ -1,4 +1,4 @@
;;; mu4e-headers.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
;;; mu4e-headers.el -- part of mu4e -*- lexical-binding: t -*-
;; Copyright (C) 2011-2022 Dirk-Jan C. Binnema
@ -41,6 +41,7 @@
(require 'mu4e-vars)
(require 'mu4e-mark)
(require 'mu4e-context)
(require 'mu4e-contacts)
(require 'mu4e-search)
(require 'mu4e-compose)
(require 'mu4e-actions)
@ -177,7 +178,7 @@ query have been received and are displayed."
;;; Public variables
(defvar mu4e-headers-sort-field :date
"Field to sort the headers by. Must be a symbol,
"Field to sort the headers by. A symbol:
one of: `:date', `:subject', `:size', `:prio', `:from', `:to.',
`:list'.
@ -305,10 +306,6 @@ In the format needed for `mu4e-read-option'.")
"If non-nil, report on the time it took to render the messages.
This is mostly useful for profiling.")
;;; Clear
@ -332,8 +329,9 @@ This is mostly useful for profiling.")
"Turn the list of contacts CONTACTS (with elements (NAME . EMAIL)
into a string."
(mapconcat
(lambda (ct)
(let ((name (car ct)) (email (cdr ct)))
(lambda (contact)
(let ((name (mu4e-contact-name contact))
(email (mu4e-contact-email contact)))
(or name email "?"))) contacts ", "))
(defun mu4e~headers-thread-prefix-map (type)
@ -503,23 +501,20 @@ while our display may be different)."
;;; Special headers
(defconst mu4e-headers-from-or-to-prefix '("" . "To ")
"Prefix for the :from-or-to field.
It's a cons cell with the car element being the From: prefix, the
cdr element the To: prefix.")
(defun mu4e~headers-from-or-to (msg)
"When the from address for message MSG is one of the the user's addresses,
"Get the From: address from MSG if not one of user's; otherwise get To:.
When the from address for message MSG is one of the the user's addresses,
\(as per `mu4e-personal-address-p'), show the To address;
otherwise ; show the from address; prefixed with the appropriate
`mu4e-headers-from-or-to-prefix'."
(let ((addr (cdr-safe (car-safe (mu4e-message-field msg :from)))))
(if (and addr (mu4e-personal-address-p addr))
(concat (cdr mu4e-headers-from-or-to-prefix)
(mu4e~headers-contact-str (mu4e-message-field msg :to)))
(concat (car mu4e-headers-from-or-to-prefix)
(mu4e~headers-contact-str (mu4e-message-field msg :from))))))
(let* ((from1 (car-safe (mu4e-message-field msg :from)))
(from1-addr (and from1 (mu4e-contact-email from1)))
(is-user (and from1-addr (mu4e-personal-address-p from1-addr))))
(if is-user
(concat "To " (mu4e~headers-contact-str (mu4e-message-field msg :to)))
(mu4e~headers-contact-str (mu4e-message-field msg :from)))))
(defun mu4e~headers-human-date (msg)
"Show a 'human' date.
If the date is today, show the time, otherwise, show the
@ -1406,7 +1401,8 @@ matching messages with that mark."
(let* ((value (mu4e-msg-field msg field)))
(if (member field '(:to :from :cc :bcc :reply-to))
(cl-find-if (lambda (contact)
(let ((name (car contact)) (email (cdr contact)))
(let ((name (mu4e-contact-name contact))
(email (mu4e-contact-email contact)))
(or (and name (string-match pattern name))
(and email (string-match pattern email))))) value)
(string-match pattern (or value ""))))))))

View File

@ -504,6 +504,10 @@ in an external program."
(lambda () (ignore-errors (delete-file tmpfile))))
tmpfile))
(defsubst mu4e-is-mode-or-derived-p (mode)
"Is the current mode equal to MODE or derived from it?"
(or (eq major-mode 'mode) (derived-mode-p mode)))
(defun mu4e-display-manual ()
"Display the mu4e manual page for the current mode.
Or go to the top level if there is none."

View File

@ -96,7 +96,7 @@
(defun mu4e~icalendar-has-email (email list)
"Check that EMAIL is in LIST."
(let ((email (downcase email)))
(cl-find-if (lambda (c) (let ((e (cdr c)))
(cl-find-if (lambda (c) (let ((e (mu4e-contact-email c)))
(and (stringp e) (string= email (downcase e)))))
list)))

View File

@ -27,6 +27,7 @@
;;; Code:
(require 'mu4e-vars)
(require 'mu4e-contacts)
(require 'flow-fill)
(require 'shr)
@ -54,9 +55,9 @@ Returns nil if the field does not exist.
A message plist looks something like:
\(:docid 32461
:from ((\"Nikola Tesla\" . \"niko@example.com\"))
:to ((\"Thomas Edison\" . \"tom@example.com\"))
:cc ((\"Rupert The Monkey\" . \"rupert@example.com\"))
:from ((:name \"Nikola Tesla\" :email \"niko@example.com\"))
:to ((:name \"Thomas Edison\" :email \"tom@example.com\"))
:cc ((:name \"Rupert The Monkey\" :email \"rupert@example.com\"))
:subject \"RE: what about the 50K?\"
:date (20369 17624 0)
:size 4337
@ -74,7 +75,9 @@ A message plist looks something like:
:body-txt \"Hi Tom, ...\"
\)).
Some notes on the format:
- The address fields are lists of pairs (NAME . EMAIL), where NAME can be nil.
- The address fields are lists of plist (:name NAME :email EMAIL),
where the :name part can be absent. The `mu4e-contact-name' and
`mu4e-contact-email' accessors can be useful for this.
- The date is in format emacs uses in `current-time'
- Attachments are a list of elements with fields :index (the number of
the MIME-part), :name (the file name, if any), :mime-type (the
@ -134,7 +137,7 @@ This is equivalent to:
)
(defun mu4e-message-contact-field-matches (msg cfield rx)
"Does MSG's contact-field CFIELD match rx?
"Does MSG's contact-field CFIELD match regexp RX?
Check if any of the of the CFIELD in MSG matches RX. I.e.
anything in field CFIELD (either :to, :from, :cc or :bcc, or a
list of those) of msg MSG matches (with their name or e-mail
@ -142,8 +145,10 @@ address) regular expressions RX. If there is a match, return
non-nil; otherwise return nil. RX can also be a list of regular
expressions, in which case any of those are tried for a match."
(if (and cfield (listp cfield))
(or (mu4e-message-contact-field-matches msg (car cfield) rx)
(mu4e-message-contact-field-matches msg (cdr cfield) rx))
(or (mu4e-message-contact-field-matches
msg (mu4e-contact-name cfield) rx)
(mu4e-message-contact-field-matches
msg (mu4e-contact-email cfield) rx))
(when cfield
(if (listp rx)
;; if rx is a list, try each one of them for a match
@ -153,7 +158,8 @@ expressions, in which case any of those are tried for a match."
;; not a list, check the rx
(seq-find
(lambda (ct)
(let ((name (car ct)) (email (cdr ct))
(let ((name (mu4e-contact-name ct))
(email (mu4e-contact-email ct))
;; the 'rx' may be some `/rx/` from mu4e-personal-addresses;
;; so let's detect and extract in that case.
(rx (if (string-match-p "^\\(.*\\)/$" rx)
@ -170,7 +176,8 @@ of the of the contacts in field CFIELD (either :to, :from, :cc or
:bcc) of msg MSG matches *me*, that is, any of the addresses for
which `mu4e-personal-address-p' return t. Returns the contact
cell that matched, or nil."
(seq-find (lambda (cell) (mu4e-personal-address-p (cdr cell)))
(seq-find (lambda (cell)
(mu4e-personal-address-p (mu4e-contact-email cell)))
(mu4e-message-field msg cfield)))
(defun mu4e-message-sent-by-me (msg)

View File

@ -1,6 +1,6 @@
;;; mu4e-org -- Org-links to mu4e messages/queries -*- lexical-binding: t -*-
;; Copyright (C) 2012-2021 Dirk-Jan C. Binnema
;; Copyright (C) 2012-2022 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
@ -29,6 +29,7 @@
(require 'org)
(require 'mu4e-view)
(require 'mu4e-contacts)
(defgroup mu4e-org nil
@ -79,25 +80,23 @@ the current query; otherwise, it links to the message at point.")
(date (format-time-string "%FT%T" (plist-get msg :date)))
(msgid (or (plist-get msg :message-id)
(mu4e-error "Cannot link message without message-id")))
(name-or-addr (lambda (addr) (or (car-safe addr) (cdr-safe addr))))
(full-address (lambda(addr)
(when addr
(if-let ((name (car addr)))
(format "%s <%s>" name (cdr addr))
(format "%s" (cdr addr)))))))
(org-store-link-props
:type "mu4e"
:date date
:from (funcall full-address from)
:fromnameoraddress (funcall name-or-addr from) ;; mu4e-specific
:maildir (plist-get msg :maildir)
:message-id msgid
:path (plist-get msg :path)
:subject (plist-get msg :subject)
:to (funcall full-address to)
:tonameoraddress (funcall name-or-addr to) ;; mu4e-specific
:link (concat "mu4e:msgid:" msgid)
:description (funcall mu4e-org-link-desc-func msg))))
(props `(:type "mu4e"
:date ,date
:from ,(mu4e-contact-full from)
:fromname ,(mu4e-contact-name from)
:fromnameoraddress ,(or (mu4e-contact-name from)
(mu4e-contact-email from)) ;; mu4e-specific
:maildir ,(plist-get msg :maildir)
:message-id ,msgid
:path ,(plist-get msg :path)
:subject ,(plist-get msg :subject)
:to ,(mu4e-contact-full to)
:tonameoraddress ,(or (mu4e-contact-name to)
(mu4e-contact-email to)) ;; mu4e-specific
:link ,(concat "mu4e:msgid:" msgid)
:description ,(funcall mu4e-org-link-desc-func msg))))
(message "PROPS %S" props)
(apply #'org-store-link-props props)))
(defun mu4e-org-store-link ()
"Store a link to a mu4e message or query.
@ -105,13 +104,15 @@ It links to the last known query when in `mu4e-headers-mode' with
`mu4e-org-link-query-in-headers-mode' set; otherwise it links to
a specific message, based on its message-id, so that links stay
valid even after moving the message around."
(when (derived-mode-p 'mu4e-view-mode 'mu4e-headers-mode)
(if (and (derived-mode-p 'mu4e-headers-mode)
mu4e-org-link-query-in-headers-mode)
(mu4e--org-store-link-query)
(when (mu4e-message-at-point)
(message "%S" (mu4e--org-store-link-message))
(mu4e--org-store-link-message)))))
(let ((view-mode-p (mu4e-is-mode-or-derived-p 'mu4e-view-mode))
(headers-mode-p (mu4e-is-mode-or-derived-p 'mu4e-headers-mode))
(message-p (mu4e-message-at-point)))
(if view-mode-p
(mu4e--org-store-link-message)
(if headers-mode-p
(if (or (not message-p) mu4e-org-link-query-in-headers-mode)
(mu4e--org-store-link-query)
(mu4e--org-store-link-message))))))
(defun mu4e-org-open (link)
"Open the org LINK.

View File

@ -211,15 +211,20 @@ I.e. a message with the draft flag set."
:shortname "Cc"
:help "Carbon-Copy recipients for the message"
:sortable t))
(:changed
. (:name "Changed"
:shortname "Chg"
:help "Date/time when the message was changed most recently"
:sortable t))
(:date
. (:name "Date"
:shortname "Date"
:help "Date/time when the message was written"
:help "Date/time when the message was sent"
:sortable t))
(:human-date
. (:name "Date"
:shortname "Date"
:help "Date/time when the message was written."
:help "Date/time when the message was sent"
:sortable :date))
(:flags
. (:name "Flags"
@ -314,7 +319,7 @@ one of the addresses in `(mu4e-personal-addresses)', in which
case it will be equal to `:to'.
Furthermore, the property `:sortable' determines whether we can
sort by this field. This can be either a boolean (nil or t), or a
sort by this field. This can be either a boolean (nil or t), or a
symbol for /another/ field. For example, the `:human-date' field
uses `:date' for that.