6

I'm using mu4e for my e-mail, and am very happy with it. However, now I need to copy e-mail messages from one Maildir to another, instead of moving them. However, in the mu4e documentation, I could not find anything about copying (i.e., duplicating and then moving one instance) of a message.

Did I overlook something, or is this indeed not possible?

  • Nothing is impossible. If it is missing you can program it - this is what is great about Emacs and open source...! There is a function mu4e~proc-add defined in mu4e-proc.el which perhaps could serve that purpose, but I am not sure how to use it (yet). It's basically a wrapper for mu's add command (see man mu-server). – armando.sano Dec 13 '17 at 6:47
  • Just tested it - it seems add does the same thing as move, just with a different syntax (i.e. adding a message to a target maildir removes this message from the source maildir). Not sure, but one way might simply be to duplicate the file(s) corresponding to your message on your local file system, change their filenames (see e.g. mu4e-change-filenames-when-moving and update the index? – armando.sano Dec 13 '17 at 12:15
  • Copying the message file on your local file system, or adding an 'action' to do it is what the developer of mu4e preconizes too. – armando.sano Dec 13 '17 at 13:05
1

Here is a way to do it using marks, which also works for bulk copying messages to another maildir. Add the following to your .emacs:

;; Function to interactively prompt for a destination (minimally changed from mu4e~mark-get-move-target() )
(defun my~mark-get-copy-target ()                 
   "Ask for a copy target, and propose to create it if it does not exist."                                   
   (interactive)                                                                                             
   ;;  (mu4e-message-at-point) ;; raises error if there is none                                              
   (let* ((target (mu4e-ask-maildir "Copy message to: "))                                                    
      (target (if (string= (substring target 0 1) "/")                                                      
            target                                                                                          
            (concat "/" target)))                                                                           
      (fulltarget (concat mu4e-maildir target)))                                                            
    (when (or (file-directory-p fulltarget)                                                                 
        (and (yes-or-no-p                                                                                   
           (format "%s does not exist.  Create now?" fulltarget))                                           
          (mu4e~proc-mkdir fulltarget)))                                                                    
      target)))                                                                                             

;; Function to duplicate a message given by its docid, msg, and that will be copied to target when the mark is executed.
(defun copy-message-to-target(docid msg target)                                                             
  (let (                                                                                                    
        (new_msg_path nil) ;; local variable                                                                
        (msg_flags (mu4e-message-field msg :flags))                                                                                                       
        )                                                                                                   
    ;; 1. target is already determined interactively when executing the mark (:ask-target)                     

    ;; 2. Determine the path for the new file: we use mu4e~draft-message-filename-construct from            
    ;; mu4e-draft.el to create a new random filename, and append the original's msg_flags                   
    (setq new_msg_path (format "%s/%s/cur/%s" mu4e-maildir target (mu4e~draft-message-filename-construct    
    (mu4e-flags-to-string msg_flags))))                                                                     

    ;; 3. Copy the message using file system call (copy-file) to new_msg_path:                              
    ;; (See e.g. mu4e-draft.el > mu4e-draft-open > resend)                                             
    (copy-file (mu4e-message-field msg :path) new_msg_path)                                                 

    ;; 4. Add the information to the database (may need to update current search query with 'g' if duplicating to current box. Try also 'V' to toggle the display of duplicates) 
    (mu4e~proc-add new_msg_path (mu4e~mark-check-target target))                                              
    )                                                                                                       
  )

;; Set this up for marking: see https://www.djcbsoftware.nl/code/mu/mu4e/Adding-a-new-kind-of-mark.html
(add-to-list 'mu4e-marks                                                                                    
    '(copy                                                                                                  
     :char ("c" . "c")                                                                                      
     :prompt "copy"                                                                                         
     :ask-target  my~mark-get-copy-target                                                                 
     :action copy-message-to-target))                                                                       
(mu4e~headers-defun-mark-for copy)                                                                          
(define-key mu4e-headers-mode-map (kbd "c") 'mu4e-headers-mark-for-copy) 

Now you can mark message selections in headers view for copying to another maildir by pressing 'c'. This will prompt for a destination maildir according to your setting of the variable mu4e-maildir-shortcut. After selecting one, to execute the mark press 'x' (as usual).

NB:

  1. if you copy messages in their own maildir, this leads to duplicated messages which may not display if mu4e-headers-skip-duplicates is non-nil. To toggle, press 'V'.

  2. if you copy messages in their own maildir, you also need to refresh the search by pressing 'g'

  3. the duplicated message will have the same message id as the original message. As such, it will show as being 'related', and part of the same thread (as seen by pressing 'P'). So even if a message is copied into a different maildir, the copy might show in the original maildir if mu4e-headers-include-related is non-nil. To toggle, press 'W'.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.