contribute: Add Davide Peressoni
[worg.git] / org-contrib / org-mac-mail-link.org
blob6e7f9c52ea66845e0ead7afe7239619b718e531a
1 #+TITLE:     org-mac-mail-link.el -- Create and handle links to the selected Mail.app message
2 #+OPTIONS:   ^:{} author:Tim Visher
3 #+STARTUP: odd
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}]]
11 * Overview
13   This code will allow you to capture a TODO item based on the
14   currently selected Mail.app message using =org-capture=.
16 * Installation
18   You should simply copy the source code from this document into your
19   init file and edit it as you see fit.
21 * Usage
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
25   the capture template.
27 * Code
29   #+begin_src elisp
30   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
31   ;;; Capture template for the currently selected Mail.app message
32   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
34   (defun org-mac-mail-link-get-selected-message-subject
35       ()
36     (with-temp-buffer
37       (call-process
38        "osascript" nil t nil
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
43       ()
44     (with-temp-buffer
45       (call-process
46        "osascript" nil t nil
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
50       ;; slashes.
51       (browse-url-url-encode-chars
52        (buffer-substring-no-properties (point-min) (- (point-max) 1))
53        "[/]")))
55   (defun org-mac-mail-link-get-link-string
56       ()
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)
60                             subject)))
62   (defun org-mac-mail-link-get-body-quote-template-element
63       ()
64     (let ((body (setq body (with-temp-buffer
65                              (call-process
66                               "osascript" nil t nil
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))))))
69       (format "
71     ,#+begin_quote
72   %s
73     ,#+end_quote"
74               (string-join
75                ;; Remove duplicate empty lines
76                (seq-reduce
77                 (lambda (acc next)
78                   (if (string= next (or (car (last acc)) ""))
79                       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)
85                                 string
86                               (format "  %s" string))))
87                         (split-string body "\n"))
88                 '())
89                "\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.
98         '(("t" "TODO")
99           ("tc" "TODO Current")
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.
104            ;;
105            ;; The resulting heading looks something like
106            ;;
107            ;; ** TODO [[message:<encoded messageID>][subject]]
108            ;;
109            ;;    [2021-05-02 Sun 16:22]
110            ;;
111            ;;    #+begin_quote
112            ;;    Unwrapped
113            ;;
114            ;;    Body
115            ;;
116            ;;    Text
117            ;;    #+end_quote
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
135       (mid _)
136     (start-process "open-link" nil "open" (format "message://%%3C%s%%3E"
137                                                   mid)))
139   (defun org-mac-mail-link-add-message-links
140       ()
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))
147   #+end_src