4

I use Mu4e to do email and my emails are stored locally in a maildir. People often send me emails with large attachments. I'd like to keep the emails but not the attachments because I'm paying for storage and would like to keep cost low. What's the best way to remove attachments from selected emails?

Background: I'm using the development version of Emacs and Ubuntu 16.04.

2
  • I assume you mean on the server, not locally? It might make a difference.
    – zck
    Commented Jun 8, 2016 at 18:10
  • I mean locally in my Maildir. The change will then be propagated to the server using mbsync, but that's irrelevant to the question. I'll update the question. Thank you.
    – tmalsburg
    Commented Jun 8, 2016 at 18:12

2 Answers 2

4

I found the solution hidden in a closed issue on GitHub (thanks to @mankoff):

(defun my-remove-attachment (msg num) 
  "Remove attachment." 
  (let* ((attach (mu4e~view-get-attach msg num))
         (path (mu4e-msg-field msg :path))
         (filename (and attach (plist-get attach :name)))
         (cmd (format "altermime --input='%s' --remove='%s'"  path filename)))
    (when (and filename
               (yes-or-no-p
                (format "Are you sure you want to remove '%s'?" filename)))
      (shell-command cmd)
      (message cmd))))

(add-to-list 'mu4e-view-attachment-actions
             '("remove-attachment" . my-remove-attachment))

This adds a new "attachment action" in Mu4e. When viewing an email, press A, then r to select the action defined above, then enter the number of the attachment. The action will ask you for confirmation before deleting the attachment. The header listing the attachments is not updates but when you leave the email and reopen it, the attachment is gone.

The code assumes that the tool altermime is installed. To install it in Ubuntu, do sudo apt-get install altermime.

3
  • Thank you very much! I had to put single quotes in --input='%s' as well, since some (GMail) folders have spaces. I found that altermime also has the --removeall option, which can be useful as well.
    – AstroFloyd
    Commented Sep 20, 2019 at 16:49
  • @AstroFloyd, thank you. I updated the solution.
    – tmalsburg
    Commented Sep 23, 2019 at 14:36
  • For macOS see this thread (requires MacPorts and sudo ports install altermime). Although the Emacs fails to complete the shell command, copy-pasting the command in the *Messages* window worked well. This may happen because Emacs does not have the same initialization as the shell: get the full path to altermime from which altermime and replace format "altermime with format "/opt/local/bin/altermime for example.
    – emonigma
    Commented Sep 14, 2020 at 15:30
3

The solution given by @tmalsburg worked for me until I switched to the gnus-based message view, which is now the default.

Below is my attempt to adapt this solution to the new view mode. Note that I do not know lisp and reached that solution by trial and error. It works for me, but you should be careful when copying it.

(defun my-mime-part-filename (num)
  "Filename of MIME part numbered num in gnus-article-mode."
  ;; Check whether the specified part exists.
  (when (> num (length gnus-article-mime-handle-alist))
    (error "No such part"))
  ;; Move point to MIME part
  (when (gnus-article-goto-part num)
    ;; Get handle for MIME part at point
    (let ((handle (get-text-property (point) 'gnus-data)))
      (when handle
        ;; Return file name of handle
        (mm-handle-filename handle)
        ))))
(defun my-delete-attachment (num)
  "Remove email attachment from mu4e using altermime." 
  (let* ((path (mu4e-message-field (mu4e-message-at-point) :path))
         (filename (my-mime-part-filename num))
         (cmd (format "altermime --input='%s' --remove='%s'"  path filename)))
    (when (and filename
               (yes-or-no-p
                (format "Remove '%s'?" filename)))
      (shell-command cmd)
      (mu4e-message cmd)
      )))
(defun my-delete-all-attachments (msg)
  "Remove all email attachments in mu4e using altermime."
  (let* ((path (mu4e-message-field msg :path))
         (subject (mu4e-message-field msg :subject))
         (cmd (format "altermime --input='%s' --removeall"  path)))
    (when (yes-or-no-p
           (format "Remove all attachments from '%s'?" subject))
      (shell-command cmd)
      (mu4e-message cmd)
      )))
(add-to-list 'mu4e-view-mime-part-actions
             '(:name "delete-attachment"
                     :handler my-delete-attachment
                     :receives index))
(add-to-list 'mu4e-headers-actions
             '("Delete-all-attachments" . my-delete-all-attachments))

As I said, I do not know lisp (in any flavour) and so there are probably multiple issues with this code. Any suggestion to improve it is more than welcome. In particular, I feel that the line (filename (my-mime-part-filename num)) in my-delete-attachment could (should?) be (filename (gnus-article-part-wrapper num 'mm-handle-filename)), but that last expression returns nil.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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