-;;; sendmail.el --- mail sending commands for Emacs. -*- byte-compile-dynamic: t -*-
+;;; sendmail.el --- mail sending commands for Emacs
-;; Copyright (C) 1985-1986, 1992-1996, 1998, 2000-2011
-;; Free Software Foundation, Inc.
+;; Copyright (C) 1985-1986, 1992-1996, 1998, 2000-2013 Free Software
+;; Foundation, Inc.
;; Maintainer: FSF
;; Keywords: mail
;; Useful to set in site-init.el
;;;###autoload
-(defcustom send-mail-function 'sendmail-query-once
+(defcustom send-mail-function
+ ;; Assume smtpmail is the preferred choice if it's already configured.
+ (if (and (boundp 'smtpmail-smtp-server)
+ smtpmail-smtp-server)
+ 'smtpmail-send-it 'sendmail-query-once)
"Function to call to send the current buffer as mail.
The headers should be delimited by a line which is
not a valid RFC822 header or continuation line,
:version "24.1"
:group 'sendmail)
-(defvar sendmail-query-once-function 'query
- "Either a function to send email, or the symbol `query'.")
-
-;;;###autoload
-(defun sendmail-query-once ()
- "Send an email via `sendmail-query-once-function'.
-If `sendmail-query-once-function' is `query', ask the user what
-function to use, and then save that choice."
- (when (equal sendmail-query-once-function 'query)
- (let* ((mail-buffer (current-buffer))
- (default
- (cond
- ((or (and window-system (eq system-type 'darwin))
- (eq system-type 'windows-nt))
- 'mailclient-send-it)
- ((and sendmail-program
- (executable-find sendmail-program))
- 'sendmail-send-it)))
- (function
- (if (or (not default)
- ;; We have detected no OS-level mail senders, or we
- ;; have already configured smtpmail, so we use the
- ;; internal SMTP service.
- (and (boundp 'smtpmail-smtp-server)
- smtpmail-smtp-server))
- 'smtpmail-send-it
- ;; Query the user.
- (unwind-protect
- (progn
- (pop-to-buffer "*Mail Help*")
- (erase-buffer)
- (insert "Sending mail from Emacs hasn't been set up yet.\n\n"
- "Type `y' to configure outgoing SMTP, or `n' to use\n"
- "the default mail sender on your system.\n\n"
- "To change this again at a later date, customize the\n"
- "`send-mail-function' variable.\n")
- (goto-char (point-min))
- (if (y-or-n-p "Configure outgoing SMTP in Emacs? ")
- 'smtpmail-send-it
- default))
- (kill-buffer (current-buffer))
- (set-buffer mail-buffer)))))
- (customize-save-variable 'sendmail-query-once-function function)))
- (funcall sendmail-query-once-function))
-
;;;###autoload
(defcustom mail-header-separator (purecopy "--text follows this line--")
"Line used to separate headers from text in messages being composed."
:type 'integer
:group 'sendmail)
-;; FIXME make it really obsolete.
(defvar mail-yank-hooks nil
"Obsolete hook for modifying a citation just inserted in the mail buffer.
Each hook function can find the citation between (point) and (mark t).
And each hook function should leave point and mark around the citation
text as modified.
-
This is a normal hook, misnamed for historical reasons.
-It is semi-obsolete and mail agents should no longer use it.")
+It is obsolete and mail agents should no longer use it.")
+(make-obsolete-variable 'mail-yank-hooks 'mail-citation-hook "19.34")
;;;###autoload
(defcustom mail-citation-hook nil
(define-key map "\C-c\C-w" 'mail-signature)
(define-key map "\C-c\C-c" 'mail-send-and-exit)
(define-key map "\C-c\C-s" 'mail-send)
- (define-key map "\C-c\C-i" 'mail-attach-file)
+ (define-key map "\C-c\C-i" 'mail-insert-file)
;; FIXME add this? "b" = bury buffer. It's in the menu-bar.
;;; (define-key map "\C-c\C-b" 'mail-dont-send)
(define-key map [menu-bar mail]
(cons "Mail" (make-sparse-keymap "Mail")))
+ (define-key map [menu-bar mail attachment]
+ '("Attach File" . mail-add-attachment))
+
(define-key map [menu-bar mail fill]
'("Fill Citation" . mail-fill-yanked-message))
"Additional expressions to highlight in Mail mode.")
\f
+;;;###autoload
+(defun sendmail-query-once ()
+ "Query for `send-mail-function' and send mail with it.
+This also saves the value of `send-mail-function' via Customize."
+ ;; If send-mail-function is already setup, we're incorrectly called
+ ;; a second time, probably because someone's using an old value
+ ;; of send-mail-function.
+ (when (eq send-mail-function 'sendmail-query-once)
+ (sendmail-query-user-about-smtp))
+ (funcall send-mail-function))
+
+(defun sendmail-query-user-about-smtp ()
+ (let* ((options `(("mail client" . mailclient-send-it)
+ ,@(when (and sendmail-program
+ (executable-find sendmail-program))
+ '(("transport" . sendmail-send-it)))
+ ("smtp" . smtpmail-send-it)))
+ (choice
+ ;; Query the user.
+ (with-temp-buffer
+ (rename-buffer "*Emacs Mail Setup Help*" t)
+ (insert "\
+ Emacs is about to send an email message, but it has not been
+ configured for sending email. To tell Emacs how to send email:
+
+ - Type `"
+ (propertize "mail client" 'face 'bold)
+ "' to start your default email client and
+ pass it the message text.\n\n")
+ (and sendmail-program
+ (executable-find sendmail-program)
+ (insert "\
+ - Type `"
+ (propertize "transport" 'face 'bold)
+ "' to invoke the system's mail transport agent
+ (the `"
+ sendmail-program
+ "' program).\n\n"))
+ (insert "\
+ - Type `"
+ (propertize "smtp" 'face 'bold)
+ "' to send mail directly to an \"outgoing mail\" server.
+ (Emacs may prompt you for SMTP settings).
+
+ Emacs will record your selection and will use it thereafter.
+ To change it later, customize the option `send-mail-function'.\n")
+ (goto-char (point-min))
+ (display-buffer (current-buffer))
+ (let ((completion-ignore-case t))
+ (completing-read "Send mail via: "
+ options nil 'require-match)))))
+ (customize-save-variable 'send-mail-function
+ (cdr (assoc-string choice options t)))))
+\f
(defun sendmail-sync-aliases ()
(when mail-personal-alias-file
(let ((modtime (nth 5 (file-attributes mail-personal-alias-file))))
send-actions return-action
&rest ignored)
(if switch-function
- (let ((special-display-buffer-names nil)
- (special-display-regexps nil)
- (same-window-buffer-names nil)
- (same-window-regexps nil))
- (funcall switch-function "*mail*")))
+ (funcall switch-function "*mail*"))
(let ((cc (cdr (assoc-string "cc" other-headers t)))
(in-reply-to (cdr (assoc-string "in-reply-to" other-headers t)))
(body (cdr (assoc-string "body" other-headers t))))
;; (kill-local-variable 'enable-multibyte-characters)
(set-buffer-multibyte (default-value 'enable-multibyte-characters))
(if current-input-method
- (inactivate-input-method))
+ (deactivate-input-method))
;; Local variables for Mail mode.
(setq mail-send-actions actions)
:options '(footnote-mode))
(defvar mail-mode-abbrev-table text-mode-abbrev-table)
+(defvar mail-encode-mml)
;;;###autoload
(define-derived-mode mail-mode text-mode "Mail"
"Major mode for editing mail to be sent.
\\[mail-signature] mail-signature (insert `mail-signature-file' file).
\\[mail-yank-original] mail-yank-original (insert current message, in Rmail).
\\[mail-fill-yanked-message] mail-fill-yanked-message (fill what was yanked).
+\\[mail-insert-file] insert a text file into the message.
+\\[mail-add-attachment] attach to the message a file as binary attachment.
Turning on Mail mode runs the normal hooks `text-mode-hook' and
`mail-mode-hook' (in that order)."
(make-local-variable 'mail-reply-action)
(make-local-variable 'mail-send-actions)
(make-local-variable 'mail-return-action)
+ (make-local-variable 'mail-encode-mml)
+ (setq mail-encode-mml nil)
(setq buffer-offer-save t)
(make-local-variable 'font-lock-defaults)
(setq font-lock-defaults '(mail-font-lock-keywords t t))
(set (make-local-variable 'comment-start-skip)
(concat "^" (regexp-quote mail-yank-prefix) "[ \t]*")))
(make-local-variable 'adaptive-fill-regexp)
+ ;; Also update the paragraph-separate entry if you change this.
(setq adaptive-fill-regexp
(concat "[ \t]*[-[:alnum:]]+>+[ \t]*\\|"
adaptive-fill-regexp))
;; lines that delimit forwarded messages.
;; Lines containing just >= 3 dashes, perhaps after whitespace,
;; are also sometimes used and should be separators.
- (setq paragraph-separate (concat (regexp-quote mail-header-separator)
- "$\\|\t*\\([-|#;>* ]\\|(?[0-9]+[.)]\\)+$"
- "\\|[ \t]*[[:alnum:]]*>+[ \t]*$\\|[ \t]*$\\|"
- "--\\( \\|-+\\)$\\|"
- page-delimiter)))
+ (setq paragraph-separate
+ (concat (regexp-quote mail-header-separator)
+ ;; This is based on adaptive-fill-regexp (presumably
+ ;; the idea is to allow navigation etc of cited paragraphs).
+ "$\\|\t*[-–!|#%;>*·•‣⁃◦ ]+$"
+ "\\|[ \t]*[-[:alnum:]]*>+[ \t]*$\\|[ \t]*$\\|"
+ "--\\( \\|-+\\)$\\|"
+ page-delimiter)))
(defun mail-header-end ()
(defun mail-bury (&optional arg)
"Bury this mail buffer."
(let ((newbuf (other-buffer (current-buffer)))
- (return-action mail-return-action)
- some-rmail)
+ (return-action mail-return-action))
(bury-buffer (current-buffer))
;; If there is an Rmail buffer, return to it nicely
;; even if this message was not started by an Rmail command.
(unless return-action
(dolist (buffer (buffer-list))
- (if (eq (buffer-local-value 'major-mode buffer) 'rmail-mode)
- (setq return-action `(rmail-mail-return ,newbuf)))))
+ (if (and (eq (buffer-local-value 'major-mode buffer) 'rmail-mode)
+ (null return-action)
+ ;; Don't match message-viewer buffer.
+ (not (string-match "\\` " (buffer-name buffer))))
+ (setq return-action `(rmail-mail-return ,buffer)))))
(if (and (null arg) return-action)
(apply (car return-action) (cdr return-action))
(switch-to-buffer newbuf))))
:type '(repeat string)
:group 'sendmail)
+(declare-function mml-to-mime "mml" ())
(defun mail-send ()
"Send the message in the current buffer.
(error "Invalid header line (maybe a continuation line lacks initial whitespace)"))
(forward-line 1)))
(goto-char opoint)
+ (when mail-encode-mml
+ (mml-to-mime)
+ (setq mail-encode-mml nil))
(run-hooks 'mail-send-hook)
(message "Sending...")
(funcall send-mail-function)
;;;###autoload
(defvar sendmail-coding-system nil
- "*Coding system for encoding the outgoing mail.
+ "Coding system for encoding the outgoing mail.
This has higher priority than the default `buffer-file-coding-system'
and `default-sendmail-coding-system',
but lower priority than the local value of `buffer-file-coding-system'.
(cons selected mm-coding-system-priorities)
mm-coding-system-priorities))
(tick (buffer-chars-modified-tick))
+ ;; Many mailers, including Gnus, passes a message of which
+ ;; the header is already encoded, so this is necessary to
+ ;; prevent it from being encoded again.
(rfc2047-encode-encoded-words nil))
(rfc2047-encode-message-header)
(= tick (buffer-chars-modified-tick)))))
(defun mail-sent-via ()
"Make a Sent-via header line from each To or CC header line."
+ (declare (obsolete "nobody can remember what it is for." "24.1"))
(interactive)
(save-excursion
;; put a marker at the end of the header
(point)))))
;; Insert a copy, with altered header field name.
(insert-before-markers "Sent-via:" to-line))))))
-
-(make-obsolete 'mail-sent-via "nobody can remember what it is for." "24.1")
-
\f
(defun mail-to ()
"Move point to end of To field, creating it if necessary."
and don't delete any header fields."
(interactive "P")
(and (consp mail-reply-action)
- (eq (car mail-reply-action) 'insert-buffer)
+ (memq (car mail-reply-action)
+ '(rmail-yank-current-message insert-buffer))
(with-current-buffer (nth 1 mail-reply-action)
(or (mark t)
(error "No mark set: %S" (current-buffer))))
(split-line mail-yank-prefix))
\f
-(defun mail-attach-file (&optional file)
+(defun mail-insert-file (&optional file)
"Insert a file at the end of the buffer, with separator lines around it."
(interactive "fAttach file: ")
(save-excursion
(insert-file-contents file)
(or (bolp) (newline))
(goto-char start))))
+
+(define-obsolete-function-alias 'mail-attach-file 'mail-insert-file "24.1")
+
+(declare-function mml-attach-file "mml"
+ (file &optional type description disposition))
+(declare-function mm-default-file-encoding "mm-encode" (file))
+
+(defun mail-add-attachment (file)
+ "Add FILE as a MIME attachment to the end of the mail message being composed."
+ (interactive "fAttach file: ")
+ (mml-attach-file file
+ (or (mm-default-file-encoding file)
+ "application/octet-stream") nil)
+ (setq mail-encode-mml t))
+
\f
;; Put these commands last, to reduce chance of lossage from quitting
;; in middle of loading the file.
-;;;###autoload (add-hook 'same-window-buffer-names (purecopy "*mail*"))
-;;;###autoload (add-hook 'same-window-buffer-names (purecopy "*unsent mail*"))
-
;;;###autoload
(defun mail (&optional noerase to subject in-reply-to cc replybuffer
actions return-action)
This is how Rmail arranges to mark messages `answered'."
(interactive "P")
(if (eq noerase 'new)
- (pop-to-buffer (generate-new-buffer "*mail*"))
+ (pop-to-buffer-same-window (generate-new-buffer "*mail*"))
(and noerase
(not (get-buffer "*mail*"))
(setq noerase nil))
- (pop-to-buffer "*mail*"))
+ (pop-to-buffer-same-window "*mail*"))
;; Avoid danger that the auto-save file can't be written.
(let ((dir (expand-file-name
(dired-noselect file-name
(concat dired-listing-switches " -t"))))
(save-selected-window
- (select-window (display-buffer dispbuf t))
+ (switch-to-buffer-other-window dispbuf)
(goto-char (point-min))
(forward-line 2)
(dired-move-to-filename)
(defun mail-other-window (&optional noerase to subject in-reply-to cc replybuffer sendactions)
"Like `mail' command, but display mail buffer in another window."
(interactive "P")
- (let ((pop-up-windows t)
- (special-display-buffer-names nil)
- (special-display-regexps nil)
- (same-window-buffer-names nil)
- (same-window-regexps nil))
- (pop-to-buffer "*mail*"))
+ (switch-to-buffer-other-window "*mail*")
(mail noerase to subject in-reply-to cc replybuffer sendactions))
;;;###autoload
(defun mail-other-frame (&optional noerase to subject in-reply-to cc replybuffer sendactions)
"Like `mail' command, but display mail buffer in another frame."
(interactive "P")
- (let ((pop-up-frames t)
- (special-display-buffer-names nil)
- (special-display-regexps nil)
- (same-window-buffer-names nil)
- (same-window-regexps nil))
- (pop-to-buffer "*mail*"))
+ (switch-to-buffer-other-frame "*mail*")
(mail noerase to subject in-reply-to cc replybuffer sendactions))
;; Do not add anything but external entries on this page.
(provide 'sendmail)
+;; Local Variables:
+;; byte-compile-dynamic: t
+;; coding: utf-8
+;; End:
+
;;; sendmail.el ends here