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?

andreas-h
  • 1,559
  • 13
  • 22
  • 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 06: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](https://groups.google.com/forum/#!topic/mu-discuss/d3WEytElsr4). – armando.sano Dec 13 '17 at 13:05

1 Answers1

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

armando.sano
  • 151
  • 4