読者です 読者をやめる 読者になる 読者になる

ichiroc subset

書きながら考える・考えをまとめる場所

Outlook のメールを org-mode の TODO に連携させる(org-protocol版)

背景

Outlook のメールを org-mode の TODO に連携させる の改良版。

前回は直接アジェンダファイルを更新していたが、org-protocolを利用すると、よりスマートに対応出来る。

  • アジェンダファイルを再読込しなくても、更新が反映される
  • 手元での更新と、Outlookからの更新で衝突が無い
  • 書き出すテンプレートを簡単に設定出来る

方針

Outlook からの更新はorg-protocolを使用して行う。

  • Outlookにマクロを登録して、メール画から簡単にEmacsに送れるようにする
  • org-mode上で、Outlookのメールにリンクして直接開けるようにする

手順

  • org-protocolをダウンロード
    • list-package から org-protocol-jekyll を使用する(自分はどっかから落としてきた)
  • Windowsにorg-protocol:/を関連付けする
  • Emacsでorg-protocolを受け取れるようにする

コード

Outlook側

Outlookのマクロに以下を登録。 メール画面からWriteToOrgFileマクロを呼び出すと実行される。 クイックアクセスツールバーにマクロを登録しておくと Alt+1 等で呼び出せて便利。

ちなみにスクリプトでは自動的に本文をクリップボードにコピーする。

Sub WriteToOrgFile()
    ' コピペスピードアップの為、最初にIEオブジェクトを生成
    Set objIE = CreateObject("InternetExplorer.Application")
    Dim mail As MailItem
    Set mail = ActiveExplorer.Selection.Item(1)
    
    Dim wshell
    Set wshell = CreateObject("WScript.Shell")
    Call objIE.navigate("about:blank")
    objIE.document.Body.innerText = mail.Body

    ' JS の encodeURI を使用する
    Dim sc
    Set sc = CreateObject("ScriptControl")
    sc.Language = "JScript"
    
    Dim js
    Set js = sc.CodeObject
    
    Subject = js.encodeURI(mail.Subject)
    Subject = Replace(Subject, "[", "「")
    Subject = Replace(Subject, "]", "」")
    
    'Subject = Replace(Subject, " ", "%20")
    Subject = Replace(Subject, "/", "%2F")
    'org-protocol:/capture:/x/outlook:$MailEntryId/$MailSubject/"  の形式でURLが実行される
    captureUrl = "org-protocol:/capture:/x/outlook:" & mail.EntryID & "/" & Subject & "/"

    ' 本文をクリップボードに格納して、後で利用出来るように非同期で実行する
    ' 事前にコピーすると capture によってクリップボードがリンクで上書きされる
    Call wshell.Run(captureUrl)
    
    ' 必要に応じて本文を使用出来るようにクリップボードにコピーする
    Body = Replace(mail.Body, vbCrLf, Chr(10))
    Body = js.encodeURI(Body)
    Call copyText(mail.Body, objIE)
End Sub

Private Sub copyText(text, objIE)
    OLECMDID_COPY = 12
    OLECMDID_SELECTALL = 17
    If objIE Is Nothing Then
        Set objIE = CreateObject("InternetExplorer.Application")
        Call objIE.navigate("about:blank")
        objIE.document.Body.innerText = text
    End If
    Call objIE.execWB(OLECMDID_SELECTALL, 0)
    Call objIE.execWB(OLECMDID_COPY, 0)
    Call objIE.Quit
End Sub

レジストリ

これを登録すると、 org-protocol:/ の形式のURLをEmacsに送れるようになる。

REGEDIT4

[HKEY_CLASSES_ROOT\org-protocol]
@="URL:Org Protocol"
"URL Protocol"=""
[HKEY_CLASSES_ROOT\org-protocol\shell]
[HKEY_CLASSES_ROOT\org-protocol\shell\open]
[HKEY_CLASSES_ROOT\org-protocol\shell\open\command]
@="\"C:\\tools\\emacs\\bin\\emacsclientw.exe\" \"%1\""

Emacsのパスは環境に合わせて変える。

Emacs

前回と同じスクリプト

;; outlook 形式のURLを開く
;; see http://lists.gnu.org/archive/html/emacs-orgmode/2008-08/msg00172.html
(defun org-open-outlook-url (uid)
  "Open an outlook format url"
  (interactive "sGUID: ")
  (w32-shell-execute nil (format "outlook:%s" uid)))
(org-add-link-type "outlook" 'org-open-outlook-url)

;; org-protocol
;; see http://orgmode.org/worg/org-contrib/org-protocol.html
(require 'org-protocol)

CaptureのTemplateの設定。必要に応じてカスタマイズ。

(add-to-list 'org-capture-templates (quote ( ("x" "From external" entry (file+headline (concat my-project-directory "org/tasks.org") "*Task Stuck*") "* ACTN %?%a   :outlook:
  :PROPERTIES:
  :CREATED_AT: %U
  :END:
  %c
  %i" :empty-lines 1 t TODO))))

課題

org-protocolはemacsclientを使用してURLをEmacsに送る。 実行後、何故かemacsclientのプロセスが残ってしまう。 メモリなどは影響が無いが、気持ち悪い。

まとめ

前回より大分スマートになった。 あとはプロセスが自動的に消えれば完璧なんだけど・・。