Download
(require 'org)
(require 'org-protocol)
(defgroup outlook-org nil
"Org Outlook"
:group 'org-mode)
(defcustom org-outlook-location (w32-short-file-name "c:/Program Files/Microsoft Office/OFFICE12/OFFICE12/OUTLOOK.exe")
"* Microsoft Outlook 2007 location."
:type 'string
:group 'outlook-org)
(defcustom org-outlook-capture 'org-capture
"Capturing system for org-protocol outlook: subprotocol. Supports org-capture"
:type 'sexp
:group 'outlook-org)
(defcustom org-protocol-outlook-default-template-key nil
"Default template for org-capture or remember."
:type 'sexp
:group 'outlook-org)
(defun org-outlook-open (id)
"Open the Outlook item identified by ID. ID should be an Outlook GUID."
(setq debug-on-error 't)
(if (and org-outlook-location (file-exists-p org-outlook-location))
(shell-command (concat "\"" org-outlook-location "\" /select \"outlook:" id "\"&"))
(w32-shell-execute "open" (concat "outlook:" id))))
(org-add-link-type "outlook" 'org-outlook-open)
(defun org-protocol-outlook (info)
"Process an org-protocol://outlook:// style url.
The sub-protocol used to reach this function is set in
`org-protocol-protocol-alist'.
This function detects the Message ID, Subject, Sender and
optional text separated by '/'. For example either
org-protocol://outlook:/ID/Subject/SenderName/SenderAddress
or
org-protocol://outlook:/o/ID/Subject/SenderName/SenderAddress
works.
By default, it uses the character
`org-protocol-outlook-default-template-key', which should be associated
with a template in `org-capture-templates'.
To use this plugin:
- Copy the outlook macro (below) into outlook
- Modify the outlook capture template (o) to capture the email as
a task. An example is below.
(\"o\" \"org-outlook\" entry (file \"~/org/refile.org\") \"* TODO Email %c %?
%i
%U\" :clock-in t :clock-resume t)
You may also use the following placeholders
Placeholders Replacement
%:link URL of the email
%:description The title of the message
%:title The title of the message
%:initial Selected text.
%:sender Sender's name
%:sender-email Sender's Email
- (optional) Modify the folder/location that outlook moves mail into (moving
mail off the server changes the message ID. Once off the
server, the ID remains the same unless you move it back...)
- (optional) Modify the capture template used (I use ``o'')
- (optional) Make the macro CreateTaskFromItem accessable
anywhere from outlook by adding it to the quick access toolbar
and/or the standard toolbar.
Public Declare Function ShellExecute Lib \"shell32.dll\" Alias \"ShellExecuteA\" ( _
ByVal hWnd As Long, _
ByVal lpOperation As String, _
ByVal lpFile As String, _
ByVal lpParameters As String, _
ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As Long
'Slightly Modified http://www.freevbcode.com/ShowCode.Asp?ID=5137
Function URLEncode(EncodeStr As String) As String
Dim i As Integer
Dim erg As String
erg = EncodeStr
' *** First replace '%' chr
erg = Replace(erg, \"%\", Chr(1))
' *** then '+' chr
erg = Replace(erg, \"+\", Chr(2))
For i = 0 To 255
Select Case i
' *** Allowed 'regular' characters
Case 37, 43, 48 To 57, 65 To 90, 97 To 122
Case 1 ' *** Replace original %
erg = Replace(erg, Chr(i), \"%25\")
Case 2 ' *** Replace original +
erg = Replace(erg, Chr(i), \"%2B\")
Case 32
erg = Replace(erg, Chr(i), \"%20\") 'org-protocol likes %20 instead of +
Case 3 To 15
erg = Replace(erg, Chr(i), \"%0\" & Hex(i))
Case Else
erg = Replace(erg, Chr(i), \"%\" & Hex(i))
End Select
Next
URLEncode = erg
End Function
Sub CreateTaskFromItem()
Dim T As Variant
Dim Outlook As New Outlook.Application
Dim ie As Object
Set ie = CreateObject(\"InternetExplorer.Application\")
Dim orgfile As Variant
Dim Pos As Integer
Dim taskf As Object
Set myNamespace = Outlook.GetNamespace(\"MAPI\")
' Change this to be your personal folder item. If it remains
' on the server it keeps the Outlook ID originally given. If
' you move it to another folder, it will assign it to another
' ID, but keep that ID as long as you don't move it back to the
' server. (*sigh* I wish it kept the same ID.)
' Technically this is unnecessary, but with my limited exchange
' account size, I move my emails to \"Personal Folders\\@ActionTasks\" and
' then (possibly) refile from there.
Set myPersonalFolder = myNamespace.Folders.item(\"Personal Folders\")
Set allPersonalFolders = myPersonalFolder.Folders
T = \"\"
For Each Folder In allPersonalFolders
If Folder.Name = \"@ActionTasks\" Then
Set taskf = Folder
Exit For
End If
Next
' End moving message.
If Outlook.Application.ActiveExplorer.Selection.Count > 0 Then
For i = 1 To Outlook.Application.ActiveExplorer.Selection.Count
Set objMail = Outlook.ActiveExplorer.Selection.item(i)
Set objMail = objMail.Move(taskf)
objMail.Save 'Maybe this will update EntryID
' Note that o is the Outlook capture template.
T = \"org-protocol:/outlook:/o/\" + URLEncode(objMail.EntryID) _
+ \"/\" + URLEncode(objMail.Subject) _
+ \"/\" + URLEncode(objMail.SenderName) _
+ \"/\" + URLEncode(objMail.SenderEmailAddress)
ShellExecute 0, \"open\", T, vbNullString, vbNullString, vbNormalFocus
Next
End If
End Sub
"
(if (and (boundp 'org-stored-links)
(or (fboundp org-outlook-capture))
(org-protocol-do-outlook-capture info org-outlook-capture))
(message "Org-mode not loaded."))
nil)
(setq org-stored-links '())
(defun org-protocol-do-outlook-capture (info capture-func)
"Support `org-capture' and `org-remember' alike.
CAPTURE-FUNC is either the symbol `org-remember' or `org-capture'."
(let* ((parts (org-protocol-split-data info t))
(template (or (and (= 1 (length (car parts))) (pop parts))
org-outlook-protocol-default-template-key))
(url (concat "outlook:" (org-protocol-sanitize-uri (car parts))))
(type (if (string-match "^\\([a-z]+\\):" url)
(match-string 1 url)))
(title (or (cadr parts) ""))
(sender (or (caddr parts) ""))
(sender-email (or (cadddr parts) ""))
(region "")
(orglink (org-make-link-string
url (if (string-match "[^[:space:]]" (format "%s (%s)" title sender)) (format "%s (%s)" title sender) url)))
(org-capture-link-is-already-stored t)
remember-annotation-functions)
(setq org-stored-links
(cons (list url title) org-stored-links))
(kill-new orglink)
(org-store-link-props :type type
:link url
:sender sender
:sender-email sender-email
:description title
:title title
:annotation orglink
)
(raise-frame)
(funcall capture-func nil template)))
(add-to-list 'org-protocol-protocol-alist
'("outlook" :protocol "outlook"
:function org-protocol-outlook :kill-client t))
(provide 'outlook-org)