From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Eric Schulte" Subject: Re: Re: Sending org buffer as mail? Date: Thu, 16 Dec 2010 23:48:49 -0700 Message-ID: <87k4j8rj11.fsf@gmail.com> References: <4D09C7F2.8020806@gmail.com> <87sjxy168c.fsf@gmail.com> <4D09D3BB.3020508@gmail.com> <87bp4lxl60.fsf@fastmail.fm> <871v5hw5go.fsf@gmail.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Return-path: Received: from [140.186.70.92] (port=58367 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PTU84-00042C-Jx for emacs-orgmode@gnu.org; Fri, 17 Dec 2010 01:49:25 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PTU82-0002zv-Vj for emacs-orgmode@gnu.org; Fri, 17 Dec 2010 01:49:24 -0500 Received: from mail-iw0-f169.google.com ([209.85.214.169]:39062) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PTU82-0002zm-LD for emacs-orgmode@gnu.org; Fri, 17 Dec 2010 01:49:22 -0500 Received: by iwn40 with SMTP id 40so475599iwn.0 for ; Thu, 16 Dec 2010 22:49:21 -0800 (PST) List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: Matt Lundin Cc: Oscar Carlsson , Jeff Horn , emacs-orgmode@gnu.org, Rainer M Krug --=-=-= Content-Type: text/plain I'm attaching a new version of org-mime.el which incorporates Matt's function below. There are now two new functions, `org-mime-org-buffer' and `org-mime-org-subtree' each of which takes a format argument specifying the format of the final email, one of 'org, 'ascii, or 'html. So, for example the following will export the current subtree as ascii into an email body, using the MAIL_TO, MAIL_CC, and MAIL_BCC properties to build the email headers, and the headline to set the subject (both directly from Matt's function below). (defun org-mime-subtree-to-ascii () (interactive) (org-mime-org-subtree 'ascii)) Does this new version of org-mime look like it should be committed? Are there any features or changes that should be considered first? Cheers -- Eric --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=org-mime.el Content-Transfer-Encoding: quoted-printable ;;; org-mime.el --- org html export for text/html MIME emails ;; Copyright (C) 2010 Eric Schulte ;; Author: Eric Schulte ;; Keywords: mime, mail, email, html ;; Homepage: http://orgmode.org/worg/org-contrib/org-mime.php ;; Version: 0.01 ;;; License: ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; WYSWYG, html mime composition using org-mode ;; ;; For mail composed using the orgstruct-mode minor mode, this ;; provides a function for converting all or part of your mail buffer ;; to embedded html as exported by org-mode. Call `org-mime-htmlize' ;; in a message buffer to convert either the active region or the ;; entire buffer to html. ;; ;; Similarly the `org-mime-org-buffer-htmlize' function can be called ;; from within an org-mode buffer to convert the buffer to html, and ;; package the results into an email handling with appropriate MIME ;; encoding. ;; ;; you might want to bind this to a key with something like the ;; following message-mode binding ;;=20 ;; (add-hook 'message-mode-hook ;; (lambda () ;; (local-set-key "\C-c\M-o" 'org-mime-htmlize))) ;; ;; and the following org-mode binding ;;=20 ;; (add-hook 'org-mode-hook ;; (lambda () ;; (local-set-key "\C-c\M-o" 'org-mime-org-buffer-htmlize))) ;;; Code: (require 'cl) (defcustom org-mime-default-header "#+OPTIONS: latex:t\n" "Default header to control html export options, and ensure first line isn't assumed to be a title line." :group 'org-mime :type 'string) (defcustom org-mime-library 'mml "Library to use for marking up MIME elements." :group 'org-mime :type '(choice 'mml 'semi 'vm)) (defcustom org-mime-preserve-breaks t "Used as temporary value of `org-export-preserve-breaks' during mime encoding." :group 'org-mime :type 'boolean) (defcustom org-mime-fixedwith-wrap "
\n%s
\n" "Format string used to wrap a fixedwidth HTML email." :group 'org-mime :type 'string) (defcustom org-mime-html-hook nil "Hook to run over the html buffer before attachment to email. This could be used for example to post-process html elements." :group 'org-mime :type 'hook) ;; example hook, for setting a dark background in
 elements
(defun org-mime-change-element-style (element style)
  "Set new default htlm style for  elements in exported html."
  (while (re-search-forward (format "<%s" element) nil t)
    (replace-match (format "<%s style=3D\"%s\"" element style))))

(defun org-mime-change-class-style (class style)
  "Set new default htlm style for objects with classs=3DCLASS in
exported html."
  (while (re-search-forward (format "class=3D\"%s\"" class) nil t)
    (replace-match (format "class=3D\"%s\" style=3D\"%s\"" class style))))

;; ;; example addition to `org-mime-html-hook' adding a dark background
;; ;; color to 
 elements
;; (add-hook 'org-mime-html-hook
;;           (lambda ()
;;             (org-mime-change-element-style
;;              "pre" (format "color: %s; background-color: %s;"
;;                            "#E6E1DC" "#232323"))
;; 	    (org-mime-change-class-style
;;              "verse" "border-left: 2px solid gray; padding-left: 4px;")))

(defun org-mime-file (ext path id)
  "Markup a file for attachment."
  (case org-mime-library
    ('mml (format
           "<#part type=3D\"%s\" filename=3D\"%s\" id=3D\"<%s>\">\n<#/part>=
\n"
           ext path id))
    ('semi (concat
            (format
             "--[[%s\nContent-Disposition: inline;\nContent-ID: <%s>][base6=
4]]\n"
             ext id)
            (base64-encode-string
             (with-temp-buffer
               (set-buffer-multibyte nil)
               (binary-insert-encoded-file path)
               (buffer-string)))))
    ('vm "?")))

(defun org-mime-multipart (plain html)
  "Markup a multipart/alternative with text/plain and text/html
  alternatives."
  (case org-mime-library
    ('mml (format (concat "<#multipart type=3Dalternative><#part type=3Dtex=
t/plain>"
                          "%s<#part type=3Dtext/html>%s<#/multipart>\n")
                  plain html))
    ('semi (concat
            "--" "<>-{\n"
            "--" "[[text/plain]]\n" plain
            "--" "[[text/html]]\n"  html
            "--" "}-<>\n"))
    ('vm "?")))

(defun org-mime-replace-images (str current-file)
  "Replace images in html files with cid links."
  (let (html-images)
    (cons
     (replace-regexp-in-string ;; replace images in html
      "src=3D\"\\([^\"]+\\)\""
      (lambda (text)
        (format
         "src=3D\"cid:%s\""
         (let* ((url (and (string-match "src=3D\"\\([^\"]+\\)\"" text)
                          (match-string 1 text)))
                (path (expand-file-name
                       url (file-name-directory current-file)))
                (ext (file-name-extension path))
                (id (replace-regexp-in-string "[\/\\\\]" "_" path)))
           (add-to-list 'html-images
                        (org-mime-file (concat "image/" ext) path id))
           id)))
      str)
     html-images)))

(defun org-mime-htmlize (arg)
  "Export a portion of an email body composed using `mml-mode' to
html using `org-mode'.  If called with an active region only
export that region, otherwise export the entire body."
  (interactive "P")
  (let* ((region-p (org-region-active-p))
         (html-start (or (and region-p (region-beginning))
                         (save-excursion
                           (goto-char (point-min))
                           (search-forward mail-header-separator)
                           (+ (point) 1))))
         (html-end (or (and region-p (region-end))
                       ;; TODO: should catch signature...
                       (point-max)))
         (raw-body (buffer-substring html-start html-end))
         (tmp-file (make-temp-name (expand-file-name
				    "mail" temporary-file-directory)))
         (body (org-export-string raw-body 'org (file-name-directory tmp-fi=
le)))
         ;; because we probably don't want to skip part of our mail
         (org-export-skip-text-before-1st-heading nil)
         ;; because we probably don't want to export a huge style file
         (org-export-htmlize-output-type 'inline-css)
         ;; makes the replies with ">"s look nicer
         (org-export-preserve-breaks org-mime-preserve-breaks)
         ;; to hold attachments for inline html images
         (html-and-images
          (org-mime-replace-images
           (org-export-string raw-body 'html (file-name-directory tmp-file))
           tmp-file))
         (html-images (unless arg (cdr html-and-images)))
         (html (org-mime-apply-html-hook
                (if arg
                    (format org-mime-fixedwith-wrap body)
                  (car html-and-images)))))
    (delete-region html-start html-end)
    (save-excursion
      (goto-char html-start)
      (insert (org-mime-multipart body html)
              (mapconcat 'identity html-images "\n")))))

(defun org-mime-apply-html-hook (html)
  (if org-mime-html-hook
      (with-temp-buffer
        (insert html)
        (goto-char (point-min))
        (run-hooks 'org-mime-html-hook)
        (buffer-string))
    html))

(defmacro org-mime-try (&rest body)
  `(condition-case nil ,@body (error nil)))

(defun org-mime-org-subtree (&optional fmt)
  (save-restriction
    (org-narrow-to-subtree)
    (let* ((file (buffer-file-name (current-buffer)))
	   (subject (nth 4 (org-heading-components)))
	   (to (org-entry-get nil "MAIL_TO"))
	   (cc (org-entry-get nil "MAIL_CC"))
	   (bcc (org-entry-get nil "MAIL_BCC"))
	   (raw-body (buffer-substring
		      (save-excursion (goto-char (point-min))
				      (forward-line 1)
				      (when (looking-at "[ \t]*:PROPERTIES:")
					(re-search-forward ":END:" nil)
					(forward-char))
				      (point))
		      (point-max)))
	   (body (org-export-string raw-body 'org)))
      (org-mime-compose body (or fmt 'org) file to subject
			`((cc . ,cc) (bcc . ,bcc))))))

(defun org-mime-org-buffer (&optional fmt)
  (let* ((region-p (org-region-active-p))
	 (subject (org-export-grab-title-from-buffer))
         (file (buffer-file-name (current-buffer)))
         (body-start (or (and region-p (region-beginning))
                         (save-excursion (goto-char (point-min)))))
         (body-end (or (and region-p (region-end)) (point-max)))
	 (temp-body-file (make-temp-file "org-mime-export"))
	 (raw-body (buffer-substring body-start body-end))
         (body (org-export-string raw-body 'org)))
    (org-mime-compose body (or fmt 'org) file nil subject)))

(defun org-mime-compose (body fmt file &optional to subject headers)
  (require 'message)
  (message-mail to subject headers nil)
  (message-goto-body)
  (let ((text (org-export-string (org-babel-trim body) 'org)))
    (case fmt
      ('org (insert text))
      ('ascii (insert (org-export-string (concat "#+Title:\n" body)'ascii)))
      ('html (let* ((org-link-file-path-type 'absolute)
		    ;; we probably don't want to export a huge style file
		    (org-export-htmlize-output-type 'inline-css)
		    (html-and-images (org-mime-replace-images
				      (org-export-string
				       body 'html (file-name-nondirectory file))
				      file))
		    (images (cdr html-and-images))
		    (html (org-mime-apply-html-hook (car html-and-images))))
	       (insert (org-mime-multipart text html)
		       (mapconcat 'identity images "\n")))))))

(provide 'org-mime)

--=-=-=
Content-Type: text/plain


"Eric Schulte"  writes:

> Hi Matt,
>
> This looks great, how would you feel about trying to fold this into
> org-mime, or would you mind if I did so.  I've already mimicked your
> function to set subjects of outgoing emails to match the title of the
> org-mode buffer.  I think that generalizing the org-mime functions to
> operate over either subtrees or whole files, and to output either html
> or plain text should cover all use cases with maximal code re-use.
>
> Thanks for sharing this function.
>
> Cheers -- Eric
>
> Matt Lundin  writes:
>
>> Rainer M Krug  writes:
>>
>>> On 12/16/2010 09:25 AM, Jeff Horn wrote:
>>>> On Thu, Dec 16, 2010 at 3:17 AM, Oscar Carlsson
>>>>  wrote:
>>>>> And then, I can send a org-file by attaching it to a mail in Emacs. Try
>>>>> C-x m to start a new mail buffer, attach with C-c C-a and send with C-c
>>>>> C-c.
>>>
>>> Sounds very interesting - I'll try it out.
>>>
>>> C-x m looks great - I am sure I am going to use it a lot. And gmail is
>>> exactly what I want to use it for.
>>>
>>>> 
>>>> Does this attach the buffer or read it into the message? I thought the
>>>> OP wanted to read-in a buffer. 
>>>
>>> Yes - that was effectively what I am looking for: the possiblility to
>>> write my email in org mode and send the buffer content as the email text.
>>>
>>> Dream: Specify subject, to, cc, bcc (probably even attachments) as
>>> properties, press a key and the org file is send to the addresses.
>>
>> I too have been looking for this functionality for a while, so here's a
>> quick solution. When called on an Org-mode subtree, the following
>> function makes the headline the subject, exports the subtree to ascii,
>> and uses properties ("MAIL_TO", "MAIL_CC", "MAIL_BCC") to specify the
>> addressees:
>>
>> (defun my-org-subtree-to-message ()
>>   (interactive)
>>   (unless (eq major-mode 'org-mode)
>>     (error "Not in org buffer"))
>>   (let ((subject (nth 4 (org-heading-components)))
>> 	(to (org-entry-get nil "MAIL_TO"))
>> 	(cc (org-entry-get nil "MAIL_CC"))
>> 	(bcc (org-entry-get nil "MAIL_BCC"))
>> 	text)
>>     (save-excursion 
>>       (org-mark-subtree)
>>       ;; don't include title in body
>>       (forward-line)
>>       (setq text (org-export-region-as-ascii (point)
>> 					     (mark) t 'string)))
>>     (message-mail to subject `((cc . ,cc) (bcc . ,bcc)) nil)
>>     (when text 
>>       (save-excursion
>> 	(goto-char (point-max))
>> 	(insert text)))))
>>
>> With this function, you can compose emails like this:
>>
>> * My obsequious missive
>>   :PROPERTIES:
>>   :MAIL_TO:  highly_esteemed@gentlemen.net
>>   :MAIL_BCC:  peasants_united@plebeians.org
>>   :END:
>> My most noble sirs,
>>
>> I thank you for gracing this world with your beauteous presence.
>>
>> Humbly yours,
>> An Org-mode user
>>
>> Best,
>> Matt
>>
>> _______________________________________________
>> Emacs-orgmode mailing list
>> Please use `Reply All' to send replies to the list.
>> Emacs-orgmode@gnu.org
>> http://lists.gnu.org/mailman/listinfo/emacs-orgmode

--=-=-=
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Emacs-orgmode mailing list
Please use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

--=-=-=--