2

I use mu4e for email. I can attach a file to a new message with drag-and-drop or with dired (as in these directions from the manual).

I would like to code the same behavior as Mail: in the Finder, I copy the relevant file or files, go to a Mail message, and they are pasted as attachments.

I wrote this function to attach one file from the clipboard:

(defun add-attachment ()
  "Include at the end of the buffer the attachment in the
interprogram-paste-function, assuming it is from the Downloads
folder."
  (interactive)
  (let ((prev-point (point)))
    (goto-char (point-max))
    (insert (concat "\n\n"
            "<#part filename=\"/Users/username/Downloads/"
            (shell-command-to-string "pbpaste")
            "\" disposition=attachment>"
            "\n"
            "<#/part>"))
    (goto-char prev-point)))

The problem is that the file has to be in the Downloads folder. The Mail program has access to more information, such as the folder, because it attaches a document instead of pasting the filename (which is Emacs's behavior).

How can I access this information and include in Emacs the full path to the files in the clipboard?

3 Answers 3

3

this fixes problems with the previous answer:

  • it solves the hang-problem by checking for the correct data type in the clipboard and doing nothing if it is not image/png
  • it saves the image in /tmp - can be customized
  (defun my/clip-to-PNG ()
    (interactive)
    (when (string-match-p (regexp-quote "image/png") (shell-command-to-string "xclip -selection clipboard -o -t TARGETS"))
      (let
          ((image-file (concat "/tmp/" (format-time-string "tmp_%Y%m%d_%H%M%S.png"))))
        (shell-command-to-string (concat "xclip -o -selection clipboard -t image/png > " image-file))
        image-file)))

  (defun my/mu4e-attach-image-from-clipboard ()
    (interactive)
    (let ((image-file (my/clip-to-PNG)) ;; paste clipboard to temp file
          (pos (point-marker)))
      (when image-file
        (goto-char (point-max))
        (mail-add-attachment image-file)
        (goto-char pos))))

2
  • Please use a link instead of "previous answer". The presentation order of answers changes over time.
    – Drew
    Commented Aug 14, 2022 at 16:05
  • 1
    If you're getting Error during redisplay: (eval (mu4e--modeline-string)) signaled (void-variable "ctx") it means that you have to install xclip, e.g., by using apt-get install xclip (linux)
    – Ajned
    Commented May 24, 2023 at 16:34
2

I wrote this to paste images into mu4e buffers on Linux.

(defun my/clip-to-PNG ()
  (interactive)
  (let 
      ((image-file (concat default-directory "tmp/attach/" (format-time-string "tmp_%Y%m%d_%H%M%S.png"))))
    (shell-command-to-string (concat "xclip -o -selection clipboard -t image/png > " image-file))
    image-file))

(defun my/mu4e-attach-image-from-clipboard ()
  (interactive)
  (let ((image-file (my/clip-to-PNG)) ;; paste clipboard to temp file
    (pos (point-marker)))
    (goto-char (point-max))
    (mail-add-attachment image-file)
    (goto-char pos)))

Unfortunately the xclip command seems to hang if there is not an image in the clipboard (e.g. text instead). If someone can suggest why and a work-around, there is a simple fix. If the clipboard does not contain a PNG, then the command returns Error: target image/png not available. Alternatively, xclip -selection clipboard -o -t TARGETS lists all valid targets for the current clipboard selection.

Anyway, if it hangs, I just C-g and make sure the image I wanted to paste-and-attach is in the clipboard.

3
  • xclip seems unavailable on macOS, do you know the equivalent? Is it pbcopy?
    – emonigma
    Commented Jul 6, 2020 at 9:55
  • xclip may be available via brew or macports or other package managers. I'm not sure how you'd adapt this to the OS X pbcopy and pbpaste commands.
    – mankoff
    Commented Jul 6, 2020 at 16:19
  • Indeed, it's available through brew. I tested the code and the target file is empty: The file “tmp_20200708_131550.png” could not be opened because it is empty. Can xclip grab the full filepath in the clipboard? I couldn't find it, so I programmed a solution in AppleScript and ELisp.
    – emonigma
    Commented Jul 8, 2020 at 13:01
0

One solution only for macOS is to use a combination of AppleScript to get the filepaths from the clipboard, call it from Emacs with shell-command-to-string, and insert text in the buffer.

Save this AppleScript in a location such as ~/code/AppleScript/clipboard to paths.scpt:

-- get clipboard
set sel to (the clipboard as text)
set one_path to POSIX path of (the clipboard as «class furl»)

-- save old delimiters
set old_delimiters to text item delimiters

-- get multiple items
set text item delimiters to {return, linefeed}
set the_items to text items of sel

-- get directory
set text item delimiters to "/"
set the_dir to text items 1 thru -2 of one_path

-- join them
set res to ""
repeat with i from 1 to length of the_items
    set res to res & (the_dir & item i of the_items) as text
    
    if (i < length of the_items) then
        set res to res & linefeed
    end if
end repeat

-- clean up
set text item delimiters to old_delimiters

return res

And save this in the Emacs initialization file:

(defun attach ()
  "Include at the end of the buffer the attachments in the clipboard"
  (interactive)
  (let* ((clipboard (shell-command-to-string "osascript \"$HOME/code/AppleScript/clipboard to paths.scpt\""))
         (items (split-string clipboard "\n")))
    (dolist (item items)
      (insert (concat "\n\n"
                      "<#part filename=\""
                      item
                      "\" disposition=attachment>"
                      "\n"
                      "<#/part>"))
      (message "Attachment(s) included at the bottom!"))))

This solution supports multiple attachments of any type as long as they are in the Finder window.

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.