1 #+TITLE: org-mac-mail-link.el -- Create and handle links to the selected Mail.app message
2 #+OPTIONS: ^:{} author:Tim Visher
5 # This file is released by its authors and contributors under the GNU
6 # Free Documentation license v1.3 or later, code examples are released
7 # under the GNU General Public License v3 or later.
9 [[file:index.org][{Back to Worg's contibutions index}]]
13 This code will allow you to capture a TODO item based on the
14 currently selected Mail.app message using =org-capture=.
18 You should simply copy the source code from this document into your
19 init file and edit it as you see fit.
23 Activate =org-capture= however you see fit (=M-x org-capture= works
24 just fine) and then whack the keychord you have set up to activate
30 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
31 ;;; Capture template for the currently selected Mail.app message
32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
34 (defun org-mac-mail-link-get-selected-message-subject
39 "-e" "tell application \"Mail\" to get subject of item 1 of (selection as list)")
40 (buffer-substring-no-properties (point-min) (- (point-max) 1))))
42 (defun org-mac-mail-link-get-selected-message-id
47 "-e" "tell application \"Mail\" to get message id of item 1 of (selection as list)")
48 ;; This additional encoding specifically of =/= is because Mail.app
49 ;; claims to be unable to find a message if it's ID contains unencoded
51 (browse-url-url-encode-chars
52 (buffer-substring-no-properties (point-min) (- (point-max) 1))
55 (defun org-mac-mail-link-get-link-string
57 (let ((subject (org-mac-mail-link-get-selected-message-subject))
58 (message-id (org-mac-mail-link-get-selected-message-id)))
59 (org-link-make-string (format "message:%s" message-id)
62 (defun org-mac-mail-link-get-body-quote-template-element
64 (let ((body (setq body (with-temp-buffer
67 "-e" "tell application \"Mail\" to get content of item 1 of (selection as list)")
68 (buffer-substring-no-properties (point-min) (- (point-max) 1))))))
75 ;; Remove duplicate empty lines
78 (if (string= next (or (car (last acc)) ""))
80 (append acc (list next))))
81 ;; Indent each line by two spaces for inclusion in the quote
82 (mapcar (lambda (string)
83 (let ((string (string-trim string)))
84 (if (string= "" string)
86 (format " %s" string))))
87 (split-string body "\n"))
91 (require 'org-capture)
93 ;;; You may also wish to use the Customize interface for this variable
94 ;;; which is quite nice.
95 (setq org-capture-templates
96 ;; These 2-item entries are only necessary if you want to nest the
97 ;; capture template under a keychord.
100 ("tcm" "TODO Current Mail" entry
101 ;; If you maintain your TODO list in a single file this will
102 ;; place the resulting org-capture template expansion under the
103 ;; 'Inbox' heading. You may want to modify this.
105 ;; The resulting heading looks something like
107 ;; ** TODO [[message:<encoded messageID>][subject]]
109 ;; [2021-05-02 Sun 16:22]
118 (file+headline "~/your-org-todo.org" "Inbox")
119 "* TODO %(org-mac-mail-link-get-link-string)
121 %U%(org-mac-mail-link-get-body-quote-template-element)" :prepend t :immediate-finish t)))
123 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
124 ;;; Use =C-c C= as your org-capture keybinding
125 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
127 (eval-after-load 'org
128 '(org-defkey org-mode-map (kbd "C-c C") #'org-capture))
130 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
131 ;;; Teach org about opening message links
132 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
134 (defun org-mac-mail-link-open-link
136 (start-process "open-link" nil "open" (format "message://%%3C%s%%3E"
139 (defun org-mac-mail-link-add-message-links
141 (org-link-set-parameters
142 "message" :follow #'org-mac-mail-link-open-link))
144 (eval-after-load 'org
145 '(org-mac-mail-link-add-message-links))