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?

miguelmorin
  • 1,751
  • 11
  • 33

3 Answers3

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))))

bitclick
  • 41
  • 3
  • Please use a link instead of "previous answer". The presentation order of answers changes over time. – Drew Aug 14 '22 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 May 24 '23 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.

mankoff
  • 4,108
  • 1
  • 22
  • 39
  • `xclip` seems unavailable on macOS, do you know the equivalent? Is it `pbcopy`? – miguelmorin Jul 06 '20 at 09: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 Jul 06 '20 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. – miguelmorin Jul 08 '20 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.

miguelmorin
  • 1,751
  • 11
  • 33