mailclient.el 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. ;;; mailclient.el --- mail sending via system's mail client.
  2. ;; Copyright (C) 2005-2012 Free Software Foundation, Inc.
  3. ;; Author: David Reitter <david.reitter@gmail.com>
  4. ;; Keywords: mail
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;; This package allows to hand over a buffer to be sent off
  18. ;; via the system's designated e-mail client.
  19. ;; Note that the e-mail client will display the contents of the buffer
  20. ;; again for editing.
  21. ;; The e-mail client is taken to be whoever handles a mailto: URL
  22. ;; via `browse-url'.
  23. ;; Mailto: URLs are composed according to RFC2368.
  24. ;; MIME bodies are not supported - we rather expect the mail client
  25. ;; to encode the body and add, for example, a digital signature.
  26. ;; The mailto URL RFC calls for "short text messages that are
  27. ;; actually the content of automatic processing."
  28. ;; So mailclient.el is ideal for situations where an e-mail is
  29. ;; generated automatically, and the user can edit it in the
  30. ;; mail client (e.g. bug-reports).
  31. ;; To activate:
  32. ;; (setq send-mail-function 'mailclient-send-it) ; if you use `mail'
  33. ;;; Code:
  34. (require 'sendmail) ;; for mail-sendmail-undelimit-header
  35. (require 'mail-utils) ;; for mail-fetch-field
  36. (require 'browse-url)
  37. (defcustom mailclient-place-body-on-clipboard-flag
  38. (fboundp 'w32-set-clipboard-data)
  39. "If non-nil, put the e-mail body on the clipboard in mailclient.
  40. This is useful on systems where only short mailto:// URLs are
  41. supported. Defaults to non-nil on Windows, nil otherwise."
  42. :type 'boolean
  43. :group 'mail)
  44. (defun mailclient-encode-string-as-url (string)
  45. "Convert STRING to a URL, using utf-8 as encoding."
  46. (apply (function concat)
  47. (mapcar
  48. (lambda (char)
  49. (cond
  50. ((eq char ?\x20) "%20") ;; space
  51. ((eq char ?\n) "%0D%0A") ;; newline
  52. ((string-match "[-a-zA-Z0-9_:/.@]" (char-to-string char))
  53. (char-to-string char)) ;; printable
  54. (t ;; everything else
  55. (format "%%%02x" char)))) ;; escape
  56. ;; Convert string to list of chars
  57. (append (encode-coding-string string 'utf-8)))))
  58. (defvar mailclient-delim-static "?")
  59. (defun mailclient-url-delim ()
  60. (let ((current mailclient-delim-static))
  61. (setq mailclient-delim-static "&")
  62. current))
  63. (defun mailclient-gather-addresses (str &optional drop-first-name)
  64. (let ((field (mail-fetch-field str nil t)))
  65. (if field
  66. (save-excursion
  67. (let ((first t)
  68. (result ""))
  69. (mapc
  70. (lambda (recp)
  71. (setq result
  72. (concat
  73. result
  74. (if (and drop-first-name
  75. first)
  76. ""
  77. (concat (mailclient-url-delim) str "="))
  78. (mailclient-encode-string-as-url
  79. recp)))
  80. (setq first nil))
  81. (split-string
  82. (mail-strip-quoted-names field) "\, *"))
  83. result)))))
  84. (declare-function clipboard-kill-ring-save "menu-bar.el" (beg end))
  85. ;;;###autoload
  86. (defun mailclient-send-it ()
  87. "Pass current buffer on to the system's mail client.
  88. Suitable value for `send-mail-function'.
  89. The mail client is taken to be the handler of mailto URLs."
  90. (require 'mail-utils)
  91. (let ((case-fold-search nil)
  92. delimline
  93. (mailbuf (current-buffer)))
  94. (unwind-protect
  95. (with-temp-buffer
  96. (insert-buffer-substring mailbuf)
  97. ;; Move to header delimiter
  98. (mail-sendmail-undelimit-header)
  99. (setq delimline (point-marker))
  100. (if mail-aliases
  101. (expand-mail-aliases (point-min) delimline))
  102. (goto-char (point-min))
  103. ;; ignore any blank lines in the header
  104. (while (and (re-search-forward "\n\n\n*" delimline t)
  105. (< (point) delimline))
  106. (replace-match "\n"))
  107. (let ((case-fold-search t)
  108. ;; Use the external browser function to send the
  109. ;; message.
  110. (browse-url-mailto-function nil))
  111. ;; initialize limiter
  112. (setq mailclient-delim-static "?")
  113. ;; construct and call up mailto URL
  114. (browse-url
  115. (concat
  116. (save-excursion
  117. (narrow-to-region (point-min) delimline)
  118. (concat
  119. "mailto:"
  120. ;; some of the headers according to RFC822
  121. (mailclient-gather-addresses "To"
  122. 'drop-first-name)
  123. (mailclient-gather-addresses "cc" )
  124. (mailclient-gather-addresses "bcc" )
  125. (mailclient-gather-addresses "Resent-To" )
  126. (mailclient-gather-addresses "Resent-cc" )
  127. (mailclient-gather-addresses "Resent-bcc" )
  128. (mailclient-gather-addresses "Reply-To" )
  129. ;; The From field is not honored for now: it's
  130. ;; not necessarily configured. The mail client
  131. ;; knows the user's address(es)
  132. ;; (mailclient-gather-addresses "From" )
  133. ;; subject line
  134. (let ((subj (mail-fetch-field "Subject" nil t)))
  135. (widen) ;; so we can read the body later on
  136. (if subj ;; if non-blank
  137. ;; the mail client will deal with
  138. ;; warning the user etc.
  139. (concat (mailclient-url-delim) "subject="
  140. (mailclient-encode-string-as-url subj))
  141. ""))))
  142. ;; body
  143. (concat
  144. (mailclient-url-delim) "body="
  145. (mailclient-encode-string-as-url
  146. (if mailclient-place-body-on-clipboard-flag
  147. (progn
  148. (clipboard-kill-ring-save
  149. (+ 1 delimline) (point-max))
  150. (concat
  151. "*** E-Mail body has been placed on clipboard, "
  152. "please paste it here! ***"))
  153. ;; else
  154. (buffer-substring (+ 1 delimline) (point-max))))))))))))
  155. (provide 'mailclient)
  156. ;;; mailclient.el ends here