mu4e: update to use server maildir/database/addresses

Mkae mu4e-maildir and mu4e-personal-addresses obsolete, we get those
from the server.
This commit is contained in:
Dirk-Jan C. Binnema 2020-02-06 20:28:24 +02:00
parent dea4789e0e
commit e1e26d1da2
17 changed files with 791 additions and 889 deletions

View File

@ -577,7 +577,8 @@ cmd_init (MuConfig *opts, GError **err)
if (!opts->quiet) {
mu_store_print_info (store, opts->nocolor);
g_print ("\nstore created.\n"
"now you can use the index command to index some messages.\n"
"use 'mu index' to fill the database "
"with your messsages.\n"
"see mu-index(1) for details\n");
}

View File

@ -323,7 +323,6 @@ Example: +tag,+long tag,-oldtag
would add 'tag' and 'long tag', and remove 'oldtag'."
(let* (
(path (mu4e-message-field msg :path))
(maildir (mu4e-message-field msg :maildir))
(oldtags (mu4e-message-field msg :tags))
(tags-completion
(append
@ -369,7 +368,7 @@ would add 'tag' and 'long tag', and remove 'oldtag'."
path))
(mu4e-message (concat "tagging: " (mapconcat 'identity taglist ", ")))
(mu4e-refresh-message path maildir)))
(mu4e-refresh-message path)))
(defun mu4e-action-show-thread (msg)
"Show thread for message at point with point remaining on MSG.

View File

@ -1,6 +1,6 @@
;; mu4e-compose.el -- part of mu4e, the mu mail user agent for emacs -*- lexical-binding: t -*-
;;
;; Copyright (C) 2011-2019 Dirk-Jan C. Binnema
;; Copyright (C) 2011-2020 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
@ -260,8 +260,8 @@ If needed, set the Fcc header, and register the handler function."
`mu4e-sent-messages-behavior'"
mu4e-sent-messages-behavior))))
(fccfile (and mdir
(concat mu4e-maildir mdir "/cur/"
(mu4e~draft-message-filename-construct "S")))))
(concat (mu4e-root-maildir) mdir "/cur/"
(mu4e~draft-message-filename-construct "S")))))
;; if there's an fcc header, add it to the file
(when fccfile
(message-add-header (concat "Fcc: " fccfile "\n"))
@ -273,7 +273,7 @@ If needed, set the Fcc header, and register the handler function."
(old-handler message-fcc-handler-function))
(lambda (file)
(setq message-fcc-handler-function old-handler) ;; reset the fcc handler
(let ((mdir-path (concat mu4e-maildir maildir)))
(let ((mdir-path (concat (mu4e-root-maildir) maildir)))
;; Create the full maildir structure for the sent folder if it doesn't exist.
;; `mu4e~proc-mkdir` runs asynchronously but no matter whether it runs before or after
;; `write-file`, the sent maildir ends up in the correct state.
@ -817,8 +817,8 @@ draft message."
;; as default emacs mailer (define-mail-user-agent etc.)
;;;###autoload
(defun mu4e~compose-mail (&optional to subject other-headers continue
switch-function yank-action send-actions return-action)
(defun mu4e~compose-mail (&optional to subject other-headers _continue
_switch-function yank-action _send-actions _return-action)
"This is mu4e's implementation of `compose-mail'.
Quoting its docstring:
Start composing a mail message to send.

View File

@ -1,6 +1,6 @@
; mu4e-context.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
;;
;; Copyright (C) 2015-2016 Dirk-Jan C. Binnema
;; Copyright (C) 2015-2020 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
@ -31,14 +31,11 @@
(defvar smtpmail-smtp-user)
(defvar mu4e-view-date-format)
(defcustom mu4e-contexts nil "The list of `mu4e-context' objects
describing mu4e's contexts."
:group 'mu4e)
(defvar mu4e-contexts nil "The list of `mu4e-context' objects
describing mu4e's contexts.")
(defcustom mu4e-context-changed-hook nil
"Hook run just *after* the context changed."
:type 'hook
:group 'mu4e-headers)
(defvar mu4e-context-changed-hook nil
"Hook run just *after* the context changed.")
(defvar mu4e~context-current nil
"The current context; for internal use. Use
@ -238,8 +235,7 @@ non-nil."
(set (car cell) (cdr cell)))
(mu4e-context-vars context)))
(setq mu4e~context-current context)
(unless (eq mu4e-split-view 'single-window)
(mu4e~main-view-real nil nil))
(run-hooks 'mu4e-context-changed-hook)
(mu4e-message "Switched context to %s" (mu4e-context-name context)))
context))
@ -248,7 +244,7 @@ non-nil."
"When contexts are defined but there is no context yet, switch
to the first whose :match-func return non-nil. If none of them
match, return the first. For MSG and POLICY, see `mu4e-context-determine'."
(when mu4e-contexts
(when (and mu4e-contexts (not mu4e~context-current))
(let ((context (mu4e-context-determine msg policy)))
(when context (mu4e-context-switch
nil (mu4e-context-name context))))))

View File

@ -1,6 +1,6 @@
;;; mu4e-contrib.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
;;
;; Copyright (C) 2013-2016 Dirk-Jan C. Binnema
;; Copyright (C) 2013-2020 Dirk-Jan C. Binnema
;; This file is not part of GNU Emacs.
;;
@ -20,7 +20,10 @@
;;; Commentary:
;; Some user-contributed functions for mu4e
(require 'mu4e-headers)
(require 'mu4e-view)
(require 'bookmark)
(require 'eshell)
;; Contributed by sabof
(defvar bookmark-make-record-function)

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-2019 Dirk-Jan C. Binnema
;; Copyright (C) 2011-2020 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
@ -38,7 +38,7 @@
(defcustom mu4e-compose-dont-reply-to-self nil
"If non-nil, don't include self.
\(that is, member of `mu4e-user-mail-address-list') in replies."
\(that is, member of `(mu4e-personal-addresses)') in replies."
:type 'boolean
:group 'mu4e-compose)
@ -189,7 +189,7 @@ of the original, we simple copy the list form the original."
(cl-member-if
(lambda (addr)
(string= (downcase addr) (downcase (cdr to-cell))))
mu4e-user-mail-address-list))
(mu4e-personal-addresses)))
reply-to)
reply-to)))
@ -253,7 +253,7 @@ REPLY-ALL."
(cl-member-if
(lambda (addr)
(string= (downcase addr) (downcase (cdr cc-cell))))
mu4e-user-mail-address-list))
(mu4e-personal-addresses)))
cc-lst))))
cc-lst)))
@ -540,7 +540,7 @@ This is based on `mu4e-drafts-folder', which is evaluated once.")
(defun mu4e~draft-determine-path (draft-dir)
"Determines the path for a new draft file in DRAFT-DIR."
(format "%s/%s/cur/%s"
mu4e-maildir draft-dir (mu4e~draft-message-filename-construct "DS")))
(mu4e-root-maildir) draft-dir (mu4e~draft-message-filename-construct "DS")))
(defun mu4e-draft-open (compose-type &optional msg)
@ -550,12 +550,11 @@ In case of a new message (when COMPOSE-TYPE is `reply', `forward'
or re-send an existing message (when COMPOSE-TYPE is `resend').
The name of the draft folder is constructed from the
concatenation of `mu4e-maildir' and `mu4e-drafts-folder' (the
concatenation of `(mu4e-root-maildir)' and `mu4e-drafts-folder' (the
latter will be evaluated). The message file name is a unique name
determined by `mu4e-send-draft-file-name'. The initial contents
will be created from either `mu4e~draft-reply-construct', or
`mu4e~draft-forward-construct' or `mu4e~draft-newmsg-construct'."
(unless mu4e-maildir (mu4e-error "Variable mu4e-maildir not set"))
(let ((draft-dir nil))
(cl-case compose-type

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,9 @@
(require 'gnus-icalendar)
(require 'cl-lib)
(eval-when-compile (require 'mu4e-mark))
(eval-when-compile (require 'mu4e-vars))
;;;###autoload
(defun mu4e-icalendar-setup ()
"Perform the necessary initialization to use mu4e-icalendar."
@ -49,34 +52,34 @@
(cl-defmethod gnus-icalendar-event:inline-reply-buttons :around
((event gnus-icalendar-event) handle)
(if (and (boundp 'mu4e~view-rendering)
(gnus-icalendar-event:rsvp event))
(let ((method (gnus-icalendar-event:method event)))
(when (or (string= method "REQUEST") (string= method "PUBLISH"))
`(("Accept" mu4e-icalendar-reply (,handle accepted ,event))
("Tentative" mu4e-icalendar-reply (,handle tentative ,event))
("Decline" mu4e-icalendar-reply (,handle declined ,event)))))
(gnus-icalendar-event:rsvp event))
(let ((method (gnus-icalendar-event:method event)))
(when (or (string= method "REQUEST") (string= method "PUBLISH"))
`(("Accept" mu4e-icalendar-reply (,handle accepted ,event))
("Tentative" mu4e-icalendar-reply (,handle tentative ,event))
("Decline" mu4e-icalendar-reply (,handle declined ,event)))))
(cl-call-next-method event handle))))
(defun mu4e-icalendar-reply (data)
"Reply to the text/calendar event present in DATA."
;; Based on `gnus-icalendar-reply'.
(let* ((handle (car data))
(status (cadr data))
(event (caddr data))
(gnus-icalendar-additional-identities mu4e-user-mail-address-list)
(reply (gnus-icalendar-with-decoded-handle handle
(gnus-icalendar-event-reply-from-buffer
(current-buffer) status (gnus-icalendar-identities))))
(msg (mu4e-message-at-point 'noerror))
(charset (cdr (assoc 'charset (mm-handle-type handle)))))
(status (cadr data))
(event (caddr data))
(gnus-icalendar-additional-identities (mu4e-personal-addresses))
(reply (gnus-icalendar-with-decoded-handle handle
(gnus-icalendar-event-reply-from-buffer
(current-buffer) status (gnus-icalendar-identities))))
(msg (mu4e-message-at-point 'noerror))
(charset (cdr (assoc 'charset (mm-handle-type handle)))))
(when reply
(cl-labels
((fold-icalendar-buffer
()
(goto-char (point-min))
(while (re-search-forward "^\\(.\\{72\\}\\)\\(.+\\)$" nil t)
(replace-match "\\1\n \\2")
(goto-char (line-beginning-position)))))
((fold-icalendar-buffer
()
(goto-char (point-min))
(while (re-search-forward "^\\(.\\{72\\}\\)\\(.+\\)$" nil t)
(replace-match "\\1\n \\2")
(goto-char (line-beginning-position)))))
(with-current-buffer (get-buffer-create gnus-icalendar-reply-bufname)
(delete-region (point-min) (point-max))
@ -92,7 +95,7 @@
(gnus-icalendar--update-org-event event status))
(when mu4e-icalendar-diary-file
(mu4e~icalendar-insert-diary event status
mu4e-icalendar-diary-file))))))
mu4e-icalendar-diary-file))))))
(defun mu4e~icalendar-delete-citation ()
"Function passed to `mu4e-compose-cite-function' to remove the citation."
@ -104,17 +107,17 @@
"See `mu4e-sent-handler' for DOCID and PATH."
(mu4e-sent-handler docid path)
(let* ((docid (mu4e-message-field original-msg :docid))
(markdescr (assq 'trash mu4e-marks))
(action (plist-get (cdr markdescr) :action))
(target (mu4e-get-trash-folder original-msg)))
(markdescr (assq 'trash mu4e-marks))
(action (plist-get (cdr markdescr) :action))
(target (mu4e-get-trash-folder original-msg)))
(with-current-buffer (mu4e-get-headers-buffer)
(run-hook-with-args 'mu4e-mark-execute-pre-hook 'trash original-msg)
(funcall action docid original-msg target))
(when (and (mu4e~headers-view-this-message-p docid)
(buffer-live-p (mu4e-get-view-buffer)))
(buffer-live-p (mu4e-get-view-buffer)))
(switch-to-buffer (mu4e-get-view-buffer))
(or (mu4e-view-headers-next)
(kill-buffer-and-window))))))
(kill-buffer-and-window))))))
(defun mu4e-icalendar-reply-ical (original-msg event status buffer-name)
"Reply to ORIGINAL-MSG containing invitation EVENT with STATUS.
@ -123,8 +126,8 @@ STATUS values. BUFFER-NAME is the name of the buffer holding the
response in icalendar format."
(let ((message-signature nil))
(let ((mu4e-compose-cite-function #'mu4e~icalendar-delete-citation)
(mu4e-sent-messages-behavior 'delete)
(mu4e-compose-reply-recipients 'sender))
(mu4e-sent-messages-behavior 'delete)
(mu4e-compose-reply-recipients 'sender))
(mu4e~compose-handler 'reply original-msg))
;; Make sure the recipient is the organizer
(let ((organizer (gnus-icalendar-event:organizer event)))
@ -136,23 +139,23 @@ response in icalendar format."
(mml-insert-multipart "alternative")
(mml-insert-part "text/plain")
(let ((reply-event (gnus-icalendar-event-from-buffer
buffer-name mu4e-user-mail-address-list)))
buffer-name (mu4e-personal-addresses))))
(insert (gnus-icalendar-event->gnus-calendar reply-event status)))
(forward-line 1); move past closing tag
(mml-attach-buffer buffer-name "text/calendar; method=REPLY; charset=utf-8")
(message-remove-header "Subject")
(message-goto-subject)
(insert (capitalize (symbol-name status))
": " (gnus-icalendar-event:summary event))
": " (gnus-icalendar-event:summary event))
(set-buffer-modified-p nil); not yet modified by user
(when mu4e-icalendar-trash-after-reply
;; Override `mu4e-sent-handler' set by `mu4e-compose-mode' to
;; also trash the message (thus must be appended to hooks).
(add-hook
'message-sent-hook
(lambda () (setq mu4e-sent-func
(mu4e~icalendar-trash-message original-msg)))
t t))))
'message-sent-hook
(lambda () (setq mu4e-sent-func
(mu4e~icalendar-trash-message original-msg)))
t t))))
(defun mu4e~icalendar-insert-diary (event reply-status filename)
@ -161,20 +164,20 @@ REPLY-STATUS is the status of the reply. The possible values are
given in the doc of `gnus-icalendar-event-reply-from-buffer'."
;; FIXME: handle recurring events
(let* ((beg (gnus-icalendar-event:start-time event))
(beg-date (format-time-string "%d/%m/%Y" beg))
(beg-time (format-time-string "%H:%M" beg))
(end (gnus-icalendar-event:end-time event))
(end-date (format-time-string "%d/%m/%Y" end))
(end-time (format-time-string "%H:%M" end))
(summary (gnus-icalendar-event:summary event))
(location (gnus-icalendar-event:location event))
(status (capitalize (symbol-name reply-status)))
(txt (if location
(format "%s (%s)\n %s " summary status location)
(format "%s (%s)" summary status))))
(beg-date (format-time-string "%d/%m/%Y" beg))
(beg-time (format-time-string "%H:%M" beg))
(end (gnus-icalendar-event:end-time event))
(end-date (format-time-string "%d/%m/%Y" end))
(end-time (format-time-string "%H:%M" end))
(summary (gnus-icalendar-event:summary event))
(location (gnus-icalendar-event:location event))
(status (capitalize (symbol-name reply-status)))
(txt (if location
(format "%s (%s)\n %s " summary status location)
(format "%s (%s)" summary status))))
(with-temp-buffer
(if (string= beg-date end-date)
(insert beg-date " " beg-time "-" end-time " " txt "\n")
(insert beg-date " " beg-time "-" end-time " " txt "\n")
(insert beg-date " " beg-time " Start of: " txt "\n")
(insert beg-date " " end-time " End of: " txt "\n"))
(write-region (point-min) (point-max) filename t))))

View File

@ -27,6 +27,7 @@
(require 'smtpmail) ;; the queueing stuff (silence elint)
(require 'mu4e-utils) ;; utility functions
(require 'mu4e-context) ;; the context
(require 'mu4e-vars) ;; the context
(require 'cl-lib)
(defconst mu4e~main-buffer-name " *mu4e-main*"
@ -140,22 +141,31 @@ clicked."
"\n")))
(defun mu4e~key-val (key val &optional unit)
"Return a key / value pair."
(concat
" * "
(propertize (format "%-20s" key) 'face 'mu4e-header-title-face)
": "
(propertize val 'face 'mu4e-header-key-face)
(if unit
(propertize (concat " " unit) 'face 'mu4e-header-title-face)
"")
"\n"))
;; NEW
;; This is the old `mu4e~main-view' function but without
;; buffer switching at the end.
(defun mu4e~main-view-real (ignore-auto noconfirm)
(defun mu4e~main-view-real (_ignore-auto _noconfirm)
(let ((buf (get-buffer-create mu4e~main-buffer-name))
(inhibit-read-only t))
(with-current-buffer buf
(erase-buffer)
(insert
"* "
(propertize "mu4e - mu for emacs version " 'face 'mu4e-title-face)
(propertize "mu4e" 'face 'mu4e-header-key-face)
(propertize " - mu for emacs version " 'face 'mu4e-title-face)
(propertize mu4e-mu-version 'face 'mu4e-header-key-face)
(propertize "; (in store: " 'face 'mu4e-title-face)
(propertize (format "%s" (plist-get mu4e~server-props :doccount)) 'face 'mu4e-header-key-face)
(propertize " messages)" 'face 'mu4e-title-face)
"\n\n"
(propertize " Basics\n\n" 'face 'mu4e-title-face)
(mu4e~main-action-str
@ -183,9 +193,15 @@ clicked."
(mu4e~main-action-str "\t* [N]ews\n" 'mu4e-news)
(mu4e~main-action-str "\t* [A]bout mu4e\n" 'mu4e-about)
(mu4e~main-action-str "\t* [H]elp\n" 'mu4e-display-manual)
(mu4e~main-action-str "\t* [q]uit\n" 'mu4e-quit))
(mu4e-main-mode)
)))
(mu4e~main-action-str "\t* [q]uit\n" 'mu4e-quit)
"\n"
(propertize " Info\n\n" 'face 'mu4e-title-face)
(mu4e~key-val "database-path" (mu4e-database-path))
(mu4e~key-val "maildir" (mu4e-root-maildir))
(mu4e~key-val "in store"
(format "%d" (plist-get mu4e~server-props :doccount)) "messages"))
(mu4e-main-mode))))
(defun mu4e~main-view-queue ()
"Display queue-related actions in the main view."

View File

@ -1,6 +1,6 @@
;; mu4e-mark.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
;;
;; Copyright (C) 2011-2019 Dirk-Jan C. Binnema
;; Copyright (C) 2011-2020 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
@ -288,7 +288,7 @@ The following marks are available, and the corresponding props:
(target (if (string= (substring target 0 1) "/")
target
(concat "/" target)))
(fulltarget (concat mu4e-maildir target)))
(fulltarget (concat (mu4e-root-maildir) target)))
(when (or (file-directory-p fulltarget)
(and (yes-or-no-p
(format "%s does not exist. Create now?" fulltarget))
@ -368,7 +368,7 @@ user which one)."
(defun mu4e~mark-check-target (target)
"Check if TARGET exists; if not, offer to create it."
(let ((fulltarget (concat mu4e-maildir target)))
(let ((fulltarget (concat (mu4e-root-maildir) target)))
(if (not (mu4e-create-maildir-maybe fulltarget))
(mu4e-error "Target dir %s does not exist " fulltarget)
target)))

View File

@ -1,6 +1,6 @@
;;; mu4e-message.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
;;
;; Copyright (C) 2012-2018 Dirk-Jan C. Binnema
;; Copyright (C) 2012-2020 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
@ -243,11 +243,11 @@ replace with."
(with-temp-buffer
(insert body)
(goto-char (point-min))
(while (re-search-forward "[  ]" nil t)
(while (re-search-forward "[  ’]" nil t)
(replace-match
(cond
((string= (match-string 0) "") "'")
((string= (match-string 0) " ") " ")
((string= (match-string 0) "’") "'")
((string= (match-string 0) " ") " ")
(t ""))))
(buffer-string)))
@ -282,14 +282,14 @@ expressions, in which case any of those are tried for a match."
Checks whether any of the of the contacts in field
CFIELD (either :to, :from, :cc or :bcc) of msg MSG matches *me*,
that is, any of the e-mail address in
`mu4e-user-mail-address-list'. Returns the contact cell that
`(mu4e-personal-addresses)'. Returns the contact cell that
matched, or nil."
(cl-find-if
(lambda (cc-cell)
(cl-member-if
(lambda (addr)
(string= (downcase addr) (downcase (cdr cc-cell))))
mu4e-user-mail-address-list))
(mu4e-personal-addresses)))
(mu4e-message-field msg cfield)))
(defsubst mu4e-message-part-field (msgpart field)

View File

@ -1,5 +1,5 @@
;;; mu4e-org -- Org-links to mu4e messages/queries -*- lexical-binding: t -*-
;; Copyright (C) 2012-2019 Dirk-Jan C. Binnema
;; Copyright (C) 2012-2020 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>

View File

@ -180,8 +180,7 @@ The server output is as follows:
;; received a pong message
((plist-get sexp :pong)
(funcall mu4e-pong-func
(plist-get sexp :props)))
(funcall mu4e-pong-func sexp))
;; received a contacts message
;; note: we use 'member', to match (:contacts nil)
@ -253,11 +252,7 @@ Start the process if needed."
(unless (file-executable-p mu4e-mu-binary)
(mu4e-error (format "`mu4e-mu-binary' (%S) not found" mu4e-mu-binary)))
(let* ((process-connection-type nil) ;; use a pipe
(args '("server"))
(args (append args (when mu4e-mu-home (list (concat "--muhome=" mu4e-mu-home)))))
(args (append args (mapcar (lambda(addr)
(format "--my-address=%s" addr))
mu4e-user-mail-address-list))))
(args '("server")))
(setq mu4e~proc-buf "")
(setq mu4e~proc-process (apply 'start-process
mu4e~proc-name mu4e~proc-name
@ -395,15 +390,12 @@ or an error."
:skip-dups ,skip-dups
:include-related ,include-related)))
(defun mu4e~proc-index (path my-addresses cleanup lazy-check)
"Index messages on PATH with possible CLEANUP and LAZY-CHECK.
(defun mu4e~proc-index (&optional cleanup lazy-check)
"Index messages with possible CLEANUP and LAZY-CHECK.
PATH should point to some maildir directory structure.
MY-ADDRESSES is a list of 'my' email addresses (see
`mu4e-user-mail-address-list')."
(mu4e~call-mu `(index
:my-addresses ,my-addresses
:cleanup ,cleanup
:lazy-check ,lazy-check)))
(mu4e~call-mu `(index :cleanup ,cleanup :lazy-check ,lazy-check)))
(defun mu4e~proc-mkdir (path)
"Create a new maildir-directory at filesystem PATH."
@ -447,26 +439,15 @@ Returns either (:update ... ) or (:error ) sexp, which are handled my
(unless (or maildir flags)
(mu4e-error "At least one of maildir and flags must be specified"))
(unless (or (not maildir)
(file-exists-p (concat mu4e-maildir "/" maildir "/")))
(file-exists-p (concat (mu4e-root-maildir) "/" maildir "/")))
(mu4e-error "Target dir does not exist"))
(let* ((idparam (mu4e~docid-msgid-param docid-or-msgid))
(flagstr
(when flags
(concat " flags:"
(if (stringp flags) flags (mu4e-flags-to-string flags)))))
(path
(when maildir
(format " maildir:%s" (mu4e~escape maildir))))
(rename
(if (and maildir mu4e-change-filenames-when-moving)
"true" "false")))
(mu4e~call-mu `(move
:docid ,(if (stringp docid-or-msgid) nil docid-or-msgid)
:msgid ,(if (stringp docid-or-msgid) docid-or-msgid nil)
:flags ,(or flags nil)
:maildir ,(or maildir nil)
:rename ,(and maildir mu4e-change-filenames-when-moving)
:noview ,no-view))))
(mu4e~call-mu `(move
:docid ,(if (stringp docid-or-msgid) nil docid-or-msgid)
:msgid ,(if (stringp docid-or-msgid) docid-or-msgid nil)
:flags ,(or flags nil)
:maildir ,(or maildir nil)
:rename ,(and maildir mu4e-change-filenames-when-moving)
:noview ,no-view)))
(defun mu4e~proc-ping (&optional queries)
"Sends a ping to the mu server, expecting a (:pong ...) in response.

View File

@ -83,10 +83,10 @@ NODEFAULT, hour and minute fields will be nil if not given."
(defun mu4e-user-mail-address-p (addr)
"If ADDR is one of user's e-mail addresses return t, nil otherwise.
User's addresses are set in `mu4e-user-mail-address-list'. Case
User's addresses are set in `(mu4e-personal-addresses)'. Case
insensitive comparison is used."
(when (and addr mu4e-user-mail-address-list
(cl-find addr mu4e-user-mail-address-list
(when (and addr (mu4e-personal-addresses)
(cl-find addr (mu4e-personal-addresses)
:test (lambda (s1 s2)
(eq t (compare-strings s1 nil nil s2 nil nil t)))))
t))
@ -182,10 +182,10 @@ see its docstring)."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun mu4e~guess-maildir (path)
"Guess the maildir for some path, or nil if cannot find it."
(let ((idx (string-match mu4e-maildir path)))
(let ((idx (string-match (mu4e-root-maildir) path)))
(when (and idx (zerop idx))
(replace-regexp-in-string
mu4e-maildir
(mu4e-root-maildir)
""
(expand-file-name
(concat path "/../.."))))))
@ -322,7 +322,7 @@ Function will return the cdr of the list element."
(dolist (dentry dentries)
(when (and (booleanp (cadr dentry)) (cadr dentry))
(if (file-accessible-directory-p
(concat mu4e-maildir "/" mdir "/" (car dentry) "/cur"))
(concat (mu4e-root-maildir) "/" mdir "/" (car dentry) "/cur"))
(setq dirs (cons (concat mdir (car dentry)) dirs)))
(unless (member (car dentry) '("cur" "new" "tmp"))
(setq dirs (append dirs (mu4e~get-maildirs-1 path
@ -332,7 +332,7 @@ Function will return the cdr of the list element."
(defvar mu4e-cache-maildir-list nil
"Whether to cache the list of maildirs; set it to t if you find
that generating the list on the fly is too slow. If you do, you
can set `mu4e-maildir-list' to nil to force regenerating the
can set `(mu4e-root-maildir)-list' to nil to force regenerating the
cache the next time `mu4e-get-maildirs' gets called.")
(defvar mu4e-maildir-list nil
@ -344,14 +344,13 @@ relative paths (ie., /archive, /sent etc.). Most of the work is
done in `mu4e~get-maildirs-1'. Note, these results are /cached/
if `mu4e-cache-maildir-list' is customized to non-nil. In that case,
the list of maildirs will not change until you restart mu4e."
(unless mu4e-maildir (mu4e-error "`mu4e-maildir' is not defined"))
(unless (and mu4e-maildir-list mu4e-cache-maildir-list)
(setq mu4e-maildir-list
(sort
(append
(when (file-accessible-directory-p
(concat mu4e-maildir "/cur")) '("/"))
(mu4e~get-maildirs-1 mu4e-maildir "/"))
(concat (mu4e-root-maildir) "/cur")) '("/"))
(mu4e~get-maildirs-1 (mu4e-root-maildir) "/"))
(lambda (s1 s2) (string< (downcase s1) (downcase s2))))))
mu4e-maildir-list)
@ -389,7 +388,7 @@ maildirs under `mu4e-maildir'."
"Like `mu4e-ask-maildir', but check for existence of the maildir,
and offer to create it if it does not exist yet."
(let* ((mdir (mu4e-ask-maildir prompt))
(fullpath (concat mu4e-maildir mdir)))
(fullpath (concat (mu4e-root-maildir) mdir)))
(unless (file-directory-p fullpath)
(and (yes-or-no-p
(mu4e-format "%s does not exist. Create now?" fullpath))
@ -724,37 +723,27 @@ completion; for testing/debugging."
(defun mu4e~check-requirements ()
"Check for the settings required for running mu4e."
(unless (>= emacs-major-version 23)
(mu4e-error "Emacs >= 23.x is required for mu4e"))
(unless (>= emacs-major-version 25)
(mu4e-error "Emacs >= 25.x is required for mu4e"))
(when mu4e~server-props
(let ((version (plist-get mu4e~server-props :version))
(mux (plist-get mu4e~server-props :mux)))
(unless (or (string= version mu4e-mu-version) mux)
(mu4e-error "mu server has version %s, but we need %s"
version mu4e-mu-version))))
(unless (string= (mu4e-server-version) mu4e-mu-version)
(mu4e-error "mu server has version %s, but we need %s"
(mu4e-server-version) mu4e-mu-version)))
(unless (and mu4e-mu-binary (file-executable-p mu4e-mu-binary))
(mu4e-error "Please set `mu4e-mu-binary' to the full path to the mu
binary."))
(unless mu4e-maildir
(mu4e-error "Please set `mu4e-maildir' to the full path to your
Maildir directory."))
;; expand mu4e-maildir, mu4e-attachment-dir
(setq mu4e-maildir (expand-file-name mu4e-maildir))
(unless (mu4e-create-maildir-maybe mu4e-maildir)
(mu4e-error "%s is not a valid maildir directory" mu4e-maildir))
(dolist (var '(mu4e-sent-folder mu4e-drafts-folder
mu4e-trash-folder))
(unless (and (boundp var) (symbol-value var))
(mu4e-error "Please set %S" var))
(unless (functionp (symbol-value var)) ;; functions are okay, too
(let* ((dir (symbol-value var))
(path (concat mu4e-maildir dir)))
(path (concat (mu4e-root-maildir) dir)))
(unless (string= (substring dir 0 1) "/")
(mu4e-error "%S must start with a '/'" dir))
(unless (mu4e-create-maildir-maybe path)
(mu4e-error "%s (%S) does not exist" path var))))))
(defun mu4e-running-p ()
"Whether mu4e is running.
Checks whether the server process is live."
@ -787,14 +776,15 @@ nothing."
mu4e-compose-complete-only-after
mu4e~contacts-tstamp)))
(defun mu4e~pong-handler (props func)
(defun mu4e~pong-handler (data func)
"Handle 'pong' responses from the mu server."
(setq mu4e~server-props props) ;; save props from the server
(let ((doccount (plist-get props :doccount)))
(setq mu4e~server-props (plist-get data :props)) ;; save info from the server
(let ((doccount (plist-get mu4e~server-props :doccount)))
(mu4e~check-requirements)
(mu4e~context-autoswitch nil mu4e-context-policy)
(when func (funcall func))
(when (zerop doccount)
(mu4e-message "Store is empty; (re)indexing. This can take a while.") ;
(mu4e-message "Store is empty; (re)indexing. This may take a while.") ;
(mu4e-update-index))
(when (and mu4e-update-interval (null mu4e~update-timer))
(setq mu4e~update-timer
@ -811,11 +801,6 @@ non-nil). Otherwise, check various requireme`'nts, then start mu4e.
When successful, call FUNC (if non-nil) afterwards."
;; if we're already running, simply go to the main view
(unless (mu4e-running-p) ;; already running?
;; no! try to set a context, do some checks, set up pong handler and ping
;; the server maybe switch the context
(mu4e~context-autoswitch nil mu4e-context-policy)
(mu4e~check-requirements)
;; when it's visible, re-draw the main view when there are changes.
(add-hook 'mu4e-index-updated-hook
(lambda()
@ -823,7 +808,7 @@ When successful, call FUNC (if non-nil) afterwards."
(when (and (buffer-live-p mainbuf) (get-buffer-window mainbuf))
(mu4e~start 'mu4e~main-view))))))
(setq mu4e-pong-func (lambda (props) (mu4e~pong-handler props func)))
(setq mu4e-pong-func (lambda (info) (mu4e~pong-handler info func)))
(mu4e~proc-ping
(mapcar ;; send it a list of queries we'd like to see read/unread info
;; for.
@ -906,12 +891,7 @@ Also scrolls to the final line, and update the progress throbber."
(defun mu4e-update-index ()
"Update the mu4e index."
(interactive)
(unless mu4e-maildir
(mu4e-error "`mu4e-maildir' is not defined"))
(mu4e~proc-index mu4e-maildir
mu4e-user-mail-address-list
mu4e-index-cleanup
mu4e-index-lazy-check))
(mu4e~proc-index mu4e-index-cleanup mu4e-index-lazy-check))
(defvar mu4e~update-buffer nil
"Internal, store the buffer of the update process when

View File

@ -1,6 +1,6 @@
;;; mu4e-vars.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
;;
;; Copyright (C) 2011-2019 Dirk-Jan C. Binnema
;; Copyright (C) 2011-2020 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 'mu4e-meta)
(require 'message)
(declare-function mu4e-error "mu4e-utils")
(defgroup mu4e nil
"mu4e - mu for emacs"
@ -50,13 +51,8 @@ path."
:group 'mu4e
:safe 'stringp)
(defcustom mu4e-maildir (expand-file-name "~/Maildir")
"The absolute file system path to your Maildir.
Must not be a symbolic link, and after starting mu4e, cannot
change until after quitting."
:type 'directory
:safe 'stringp
:group 'mu4e)
(make-obsolete-variable 'mu4e-maildir
"determined by server; see `mu4e-root-maildir'." "1.3.8")
(defcustom mu4e-org-support t
"Support org-mode links."
@ -172,9 +168,10 @@ matched case-insensitively."
;; don't use the older vars anymore
(make-obsolete-variable 'mu4e-user-mail-address-regexp
'mu4e-user-mail-address-list "0.9.9.x")
(make-obsolete-variable 'mu4e-my-email-addresses
'mu4e-user-mail-address-list "0.9.9.x")
(make-obsolete-variable 'mu4e-user-mail-address-list
"determined by server; see `mu4e-personal-addresses'." "1.3.8")
(defcustom mu4e-use-fancy-chars nil
"When set, allow fancy (Unicode) characters for marks/threads.
@ -365,10 +362,8 @@ The setting is a symbol:
(defcustom mu4e-compose-complete-only-personal nil
"Whether to consider only 'personal' e-mail addresses for completion.
That is, addresses from messages where user was explicitly in one
of the address fields (this excludes mailing list messages). See
`mu4e-user-mail-address-list' and the mu-index manpage for
details for details (in particular, how to define your own e-mail
addresses)."
of the address fields (this excludes mailing list messages).
These addresses are the ones specified with `mu init'."
:type 'boolean
:group 'mu4e-compose)
@ -926,13 +921,42 @@ We need to keep this information around to quickly re-sort
subsets of the contacts in the completions function in
mu4e-compose.")
(defvar mu4e~server-props nil
"Properties we receive from the mu4e server process.
\(in the 'pong-handler').")
(defvar mu4e~headers-last-query nil
"The present (most recent) query.")
(defvar mu4e~server-props nil
"Information we receive from the mu4e server process \(in the 'pong-handler').")
(defun mu4e-root-maildir()
"Get the root maildir."
(let ((root-maildir (and mu4e~server-props
(plist-get mu4e~server-props :root-maildir))))
(unless root-maildir
(mu4e-error "root maildir unknown; did you start mu4e?"))
root-maildir))
(defun mu4e-database-path()
"Get the mu4e database path"
(let ((path (and mu4e~server-props
(plist-get mu4e~server-props :database-path))))
(unless path
(mu4e-error "database-path unknown; did you start mu4e?"))
path))
(defun mu4e-personal-addresses()
"Get the user's personal addresses, if any. If none are set on the server-side,
fall back to the obsolete `mu4e-user-mail-address-list'."
(let ((addrs (and mu4e~server-props
(plist-get mu4e~server-props :personal-addresses))))
(if addrs addrs mu4e-user-mail-address-list)))
(defun mu4e-server-version()
"Get the server version, which should match mu4e's."
(let ((version (and mu4e~server-props (plist-get mu4e~server-props :version))))
(unless version
(mu4e-error "version unknown; did you start mu4e?"))
version))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; our handlers funcs these handler funcs define what happens when we receive a

View File

@ -1,6 +1,6 @@
;;; mu4e-view.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
;;
;; Copyright (C) 2011-2018 Dirk-Jan C. Binnema
;; Copyright (C) 2011-2020 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
@ -392,7 +392,7 @@ article-mode."
(run-hooks 'gnus-article-decode-hook)
(let ((mu4e~view-rendering t) ; customize gnus in mu4e
(max-specpdl-size mu4e-view-max-specpdl-size)
(gnus-icalendar-additional-identities mu4e-user-mail-address-list))
(gnus-icalendar-additional-identities (mu4e-personal-addresses)))
(gnus-article-prepare-display))
(mu4e-view-mode)
(setq mu4e~view-message msg)

View File

@ -217,6 +217,7 @@ After these steps, @t{mu4e} should be ready to go!
* Requirements:: What is needed
* Installation:: How to install @t{mu} and @t{mu4e}
* Getting mail:: Getting mail from a server
* Initializing the message store:: Settings things up
* Indexing your messages:: Creating and maintaining the index
* Basic configuration:: Settings for @t{mu4e}
* Folders:: Setting up standard folders
@ -230,14 +231,14 @@ After these steps, @t{mu4e} should be ready to go!
@section Requirements
@t{mu}/@t{mu4e} are known to work on a wide variety of Unix- and
Unix-like systems, including many Linux distributions, OS X and FreeBSD,
and even on MS-Windows (with Cygwin). @command{emacs} 23 or 24
(recommended) is required, as well as
Unix-like systems, including many Linux distributions, OS X and
FreeBSD, and even on MS-Windows (with Cygwin). @command{emacs} 24 or
higher is required, as well as
Xapian@footnote{@url{https://xapian.org/}} and
GMime@footnote{@url{http://spruce.sourceforge.net/gmime/}}.
@t{mu} has optional support for the Guile 2.x (Scheme) programming
language. There are also some GUI-tools, which require GTK+ 3.x and
language. There are also some GUI-toys, which require GTK+ 3.x and
Webkit.
If you intend to compile @t{mu} yourself, you need to have the typical
@ -249,16 +250,17 @@ you also need the development packages for GTK+, Webkit and Guile.
@node Installation
@section Installation
@t{mu4e} is part of @t{mu} --- by installing the latter, the former is installed
as well. Some Linux distributions provide packaged versions of
@t{mu}/@t{mu4e}; if you can use those, there is no need to compile anything
yourself. However, if there are no packages for your distribution, if they are
outdated, or if you want to use the latest development versions, you can
follow the steps below.
@t{mu4e} is part of @t{mu} --- by installing the latter, the former is
installed as well. Some Linux distributions provide packaged versions
of @t{mu}/@t{mu4e}; if you can use those, there is no need to compile
anything yourself. However, if there are no packages for your
distribution, if they are outdated, or if you want to use the latest
development versions, you can follow the steps below.
First, you need make sure you have the necessary dependencies; the details
depend on your distribution. If you're using another distribution (or another
OS), the below can at least be helpful in identifying the packages to install.
First, you need make sure you have the necessary dependencies; the
details depend on your distribution. If you're using another
distribution (or another OS), the below can at least be helpful in
identifying the packages to install.
We provide some instructions for Debian, Ubuntu and Fedora; if those do not
apply to you, you can follow either @ref{Building from a release tarball} or
@ -356,46 +358,74 @@ through things step-by-step.
@node Getting mail
@section Getting mail
In order for @t{mu} (and, by extension, @t{mu4e}) to work, you need to have
your e-mail messages stored in a
@emph{maildir}@footnote{@url{https://en.wikipedia.org/wiki/Maildir}; in this
manual we use the term `maildir' for both the standard and the hierarchy of
maildirs that store your messages} --- a specific directory structure with
one-file-per-message. If you are already using a maildir, you are lucky. If
not, some setup is required:
In order for @t{mu} (and, by extension, @t{mu4e}) to work, you need to
have your e-mail messages stored in a
@emph{maildir}@footnote{@url{https://en.wikipedia.org/wiki/Maildir};
in this manual we use the term `maildir' for both the standard and the
hierarchy of maildirs that store your messages} --- a specific
directory structure with one-file-per-message. If you are already
using a maildir, you are lucky. If not, some setup is required:
@itemize
@item @emph{Using an external IMAP or POP server} --- if you are using an
@abbr{IMAP} or @abbr{POP} server, you can use tools like @t{getmail},
@t{fetchmail}, @t{offlineimap} or @t{isync} to download your messages into a
maildir (@file{~/Maildir}, often). Because it is such a common case, there is
a full example of setting @t{mu4e} up with @t{offlineimap} and Gmail;
@pxref{Gmail configuration}.
@t{fetchmail}, @t{offlineimap} or @t{isync} to download your messages
into a maildir (@file{~/Maildir}, often). Because it is such a common
case, there is a full example of setting @t{mu4e} up with
@t{offlineimap} and Gmail; @pxref{Gmail configuration}.
@item @emph{Using a local mail server} --- if you are using a local mail-server
(such as @t{postfix} or @t{qmail}), you can teach them to deliver into a
maildir as well, maybe in combination with @t{procmail}. A bit of googling
should be able to provide you with the details.
(such as @t{postfix} or @t{qmail}), you can teach them to deliver into
a maildir as well, maybe in combination with @t{procmail}. A bit of
googling should be able to provide you with the details.
@end itemize
@node Initializing the message store
@section Initializing the message store
The first time your run @t{mu}, you need to initialize its store
(database). The default location for that is @t{~/.cache/mu/xapian},
but you can change this using the @t{--muhome} option, and remember to
pass that to the other commands as well.
Assuming that your maildir is at @file{~/Maildir}, we issue the
following command:
@example
$ mu init --maildir=~/Maildir
@end example
Optionally, you can add some e-mail addresses, so @t{mu} recognizes
them as yours:
@example
$ mu init --maildir=~/Maildir --my-address=jim@@example.com --my-address=bob@@example.com
@end example
@t{mu} remembers the maildir and your addresses and uses them when
indexing messages. If you want to change them, you need to @t{init}
once again.
If you want to see the current values, you can use @t{mu info}.
@node Indexing your messages
@section Indexing your messages
After you have succeeded in @ref{Getting mail}, we need to @emph{index} the
messages. That is --- we need to scan the messages in the maildir and store the
information about them in a special database. We can do that from @t{mu4e} ---
@ref{Main view}, but the first time, it is a good idea to run it from the
command line, which makes it easier to verify that everything works correctly.
After you have succeeded in @ref{Getting mail} and initialized the
message database, we need to @emph{index} the messages. That is --- we
need to scan the messages in the maildir and store the information
about them in a special database.
We can do that from @t{mu4e} --- @ref{Main view}, but the first time,
it is a good idea to run it from the command line, which makes it
easier to verify that everything works correctly.
Assuming that your maildir is at @file{~/Maildir}, we issue the following
command:
@example
$ mu index --maildir=~/Maildir
$ mu index
@end example
This should scan your @file{~/Maildir}@footnote{In most cases, you do not even
need to provide the @t{--maildir=~/Maildir} since it is the default; see the
@t{mu-index} man-page for details} and fill the database, and give progress
information while doing so.
This should scan your messages and fill the database, and give
progress information while doing so.
The indexing process may take a few minutes the first time you do it
(for thousands of e-mails); afterwards it is much faster, since @t{mu}
@ -448,19 +478,15 @@ situation. See @ref{Dynamic folders} for details.}:
@lisp
;; these are actually the defaults
(setq
mu4e-maildir "~/Maildir" ;; top-level Maildir
mu4e-sent-folder "/sent" ;; folder for sent messages
mu4e-drafts-folder "/drafts" ;; unfinished messages
mu4e-trash-folder "/trash" ;; trashed messages
mu4e-refile-folder "/archive") ;; saved messages
@end lisp
Note, @code{mu4e-maildir} takes an actual filesystem-path, the other
folder names are all relative to @code{mu4e-maildir}. Also note that
this must @emph{not} be a symbolic link.
If you use @t{mu4e-context}, see @ref{Contexts and special folders} for
what that means for these special folders.
Note, the folder names are all relative to the root-maildir (see the
output of @t{mu info}). If you use @t{mu4e-context}, see @ref{Contexts
and special folders} for what that means for these special folders.
@node Retrieval and indexing
@section Retrieval and indexing with mu4e
@ -684,9 +710,9 @@ The main view looks something like the following:
Bookmarks
* [bu] Unread messages (26217/26217)
* [bt] Today's messages (2/8)
* [bw] Last 7 days (7/34)
* [bu] Unread messages (26217/26217)
* [bt] Today's messages (2/8)
* [bw] Last 7 days (7/34)
* [bp] Messages with images (276/2315)
Misc
@ -710,11 +736,11 @@ Let's walk through the menu.
First, the @emph{Basics}:
@itemize
@item @t{[j]ump to some maildir}: after pressing @key{j} (``jump''),
@t{mu4e} asks you for a maildir to visit. These are the maildirs you set in
@ref{Basic configuration} and any of your own. If you choose @key{o}
(``other'') or @key{/}, you can choose from all maildirs under
@code{mu4e-maildir}. After choosing a maildir, the messages in that maildir
are listed, in the @ref{Headers view}.
@t{mu4e} asks you for a maildir to visit. These are the maildirs you
set in @ref{Basic configuration} and any of your own. If you choose
@key{o} (``other'') or @key{/}, you can choose from all maildirs under
the root-maildir. After choosing a maildir, the messages in that
maildir are listed, in the @ref{Headers view}.
@item @t{enter a [s]earch query}: after pressing @key{s}, @t{mu4e} asks
you for a search query, and after entering one, shows the results in the
@ref{Headers view}.
@ -2630,9 +2656,8 @@ invoke those function even in that case.
the current context is also visible in the mode-line when in
headers, view or main mode.
@item You can set any kind of variable; including settings for mail servers etc.
However, settings such as @code{mu4e-maildir} and @code{mu4e-mu-home}
are not changeable after they have been set without quitting @t{mu4e}
first.
However, settings such as @code{mu4e-mu-home} are not changeable after
they have been set without quitting @t{mu4e} first.
@item @code{leave-func} (if defined) for the context we are leaving, is invoked
before the @code{enter-func} (if defined) of the
context we are entering.
@ -3512,10 +3537,6 @@ see, most of it is commented-out.
;; use mu4e for e-mail in emacs
(setq mail-user-agent 'mu4e-user-agent)
;; Only needed if your maildir is _not_ ~/Maildir
;; Must be a real dir, not a symlink
;;(setq mu4e-maildir "/home/user/Maildir")
;; these must start with a "/", and must exist
;; (i.e.. /home/user/Maildir/sent must exist)
;; you use e.g. 'mu mkdir' to make the Maildirs if they don't
@ -3549,10 +3570,8 @@ customize.
;; use mu4e for e-mail in emacs
(setq mail-user-agent 'mu4e-user-agent)
;; path to our Maildir directory
(setq mu4e-maildir "/home/user/Maildir")
;; the next are relative to `mu4e-maildir'
;; the next are relative to the root maildir
;; (see `mu info`).
;; instead of strings, they can be functions too, see
;; their docstring or the chapter 'Dynamic folders'
(setq mu4e-sent-folder "/sent"
@ -3718,9 +3737,6 @@ Next step: let's make a @t{mu4e} configuration for this:
;; use mu4e for e-mail in emacs
(setq mail-user-agent 'mu4e-user-agent)
;; default
;; (setq mu4e-maildir "~/Maildir")
(setq mu4e-drafts-folder "/[Gmail].Drafts")
(setq mu4e-sent-folder "/[Gmail].Sent Mail")
(setq mu4e-trash-folder "/[Gmail].Trash")
@ -4207,7 +4223,6 @@ github-repository.
@menu
* Fancy characters:: Non-ascii characters in the UI
* Multiple accounts:: (Obsolete) the old way to deal with multiple accounts
* Refiling messages:: Moving message to some archive folder
* Saving outgoing messages:: Automatically save sent messages
* Confirmation before sending:: Check messages before sending
@ -4242,121 +4257,6 @@ try the @emph{unicode-fonts} package:
(unicode-fonts-setup)
@end lisp
@node Multiple accounts
@section Multiple accounts
@b{Note}: for @t{mu4e} version 0.9.16 and higher, the recommended way
to deal with multiple accounts is through @t{mu4e}'s built-in
@ref{Contexts} system. For older versions, the below still works.
Using @t{mu4e} with multiple email accounts is fairly easy. Although
variables such as @code{user-mail-address}, @code{mu4e-sent-folder},
@code{message-*}, @code{smtpmail-*}, etc. typically only take one value,
it is easy to change their values using @code{mu4e-compose-pre-hook}.
The setup described here is one way of doing this (though certainly not
the only way).
This setup assumes that you have multiple mail accounts under
@code{mu4e-maildir}. As an example, we'll use @t{~/Maildir/Account1}
and @t{~/Maildir/Account2}, but the setup works just as well if
@code{mu4e-maildir} points to something else.
First, you need to make sure that all variables that you wish to change
based on user account are set to some initial value. So set up your
environment with e.g., your main account:
@lisp
(setq mu4e-sent-folder "/Account1/Saved Items"
mu4e-drafts-folder "/Account1/Drafts"
user-mail-address "my.address@@account1.example.com"
smtpmail-default-smtp-server "smtp.account1.example.com"
smtpmail-local-domain "account1.example.com"
smtpmail-smtp-server "smtp.account1.example.com"
smtpmail-stream-type 'starttls
smtpmail-smtp-service 25)
@end lisp
Then create a variable @code{my-mu4e-account-alist}, which should
contain a list for each of your accounts. Each list should start with
the account name, (which @emph{must} be identical to the account's
directory name under @t{~/Maildir}), followed by @code{(variable
value)} pairs:
@lisp
(defvar my-mu4e-account-alist
'(("Account1"
(mu4e-sent-folder "/Account1/Saved Items")
(mu4e-drafts-folder "/Account1/Drafts")
(user-mail-address "my.address@@account1.example.com")
(smtpmail-default-smtp-server "smtp.account1.example.com")
(smtpmail-local-domain "account1.example.com")
(smtpmail-smtp-user "username1")
(smtpmail-smtp-server "smtp.account1.example.com")
(smtpmail-stream-type starttls)
(smtpmail-smtp-service 25))
("Account2"
(mu4e-sent-folder "/Account2/Saved Items")
(mu4e-drafts-folder "/Account2/Drafts")
(user-mail-address "my.address@@account2.example.com")
(smtpmail-default-smtp-server "smtp.account2.example.com")
(smtpmail-local-domain "account2.example.com")
(smtpmail-smtp-user "username2")
(smtpmail-smtp-server "smtp.account2.example.com")
(smtpmail-stream-type starttls)
(smtpmail-smtp-service 587))))
@end lisp
You can put any variable you want in the account lists, just make sure
that you put in @emph{all} the variables that differ for each account.
Variables that do not differ need not be included. For example, if you
use the same SMTP server for both accounts, you don't need to include
the SMTP-related variables in @code{my-mu4e-account-alist}.
Note that some SMTP servers (such as Gmail) require the SMTP username to
match the user mail address. In this case, your mail appears to
originate from whichever SMTP account you use. Thus unless you are
certain your SMTP server does not have this requirement, you should
generally use different SMTP account credentials for each mail account.
Now, the following function can be used to select an account and set the
variables in @code{my-mu4e-account-alist} to the correct values:
@lisp
(defun my-mu4e-set-account ()
"Set the account for composing a message."
(let* ((account
(if mu4e-compose-parent-message
(let ((maildir (mu4e-message-field mu4e-compose-parent-message :maildir)))
(string-match "/\\(.*?\\)/" maildir)
(match-string 1 maildir))
(completing-read (format "Compose with account: (%s) "
(mapconcat #'(lambda (var) (car var))
my-mu4e-account-alist "/"))
(mapcar #'(lambda (var) (car var)) my-mu4e-account-alist)
nil t nil nil (caar my-mu4e-account-alist))))
(account-vars (cdr (assoc account my-mu4e-account-alist))))
(if account-vars
(mapc #'(lambda (var)
(set (car var) (cadr var)))
account-vars)
(error "No email account found"))))
@end lisp
This function then needs to be added to @code{mu4e-compose-pre-hook}:
@lisp
(add-hook 'mu4e-compose-pre-hook 'my-mu4e-set-account)
@end lisp
This way, @code{my-mu4e-set-account} is called every time you edit a
message. If you compose a new message, it simply asks you for the
account you wish to send the message from (TAB completion works). If
you're replying or forwarding a message, or editing an existing draft,
the account is chosen automatically, based on the first component of the
maildir of the message being replied to, forwarded or edited (i.e., the
directory under @t{~/Maildir}).
@node Refiling messages
@section Refiling messages