]> code.delx.au - gnu-emacs/blobdiff - lisp/mail/sendmail.el
(mail-alias-file): Add autoload cookie.
[gnu-emacs] / lisp / mail / sendmail.el
index ccc00e952da29cfdaeba46f0bfc437b12ddbb655..0f2861f8868a4afbd68081c15ff32f2298ce4be9 100644 (file)
@@ -1,6 +1,6 @@
 ;;; sendmail.el --- mail sending commands for Emacs.
 
-;; Copyright (C) 1985, 1986, 1992 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1992, 1993, 1994 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: mail
 ;; along with GNU Emacs; see the file COPYING.  If not, write to
 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
+;;; Commentary:
+
+;; This mode provides mail-sending facilities from within Emacs.  It is
+;; documented in the Emacs user's manual.
+
 ;;; Code:
 
 ;;;###autoload
@@ -40,7 +45,7 @@ Delete these headers from old message when it's inserted in a reply.")
 
 ;; Useful to set in site-init.el
 ;;;###autoload
-(defconst send-mail-function 'sendmail-send-it "\
+(defvar send-mail-function 'sendmail-send-it "\
 Function to call to send the current buffer as mail.
 The headers are be delimited by a line which is `mail-header-separator'.")
 
@@ -53,9 +58,11 @@ The headers are be delimited by a line which is `mail-header-separator'.")
 *Name of file to write all outgoing messages in, or nil for none.
 Do not use an rmail file here!  Instead, use its inbox file.")
 
+;;;###autoload
 (defvar mail-default-reply-to nil
   "*Address to insert as default Reply-to field of outgoing messages.")
 
+;;;###autoload
 (defvar mail-alias-file nil
   "*If non-nil, the name of a file to use instead of `/usr/lib/aliases'.
 This file defines aliases to be expanded by the mailer; this is a different
@@ -71,6 +78,26 @@ The alias definitions in `~/.mailrc' have this form:
 (defvar mail-yank-prefix nil
   "*Prefix insert on lines of yanked message being replied to.
 nil means use indentation.")
+(defvar mail-indentation-spaces 3
+  "*Number of spaces to insert at the beginning of each cited line.
+Used by `mail-yank-original' via `mail-yank-cite'.")
+(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.")
+
+(defvar mail-citation-hook nil
+  "*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.
+
+If this hook is entirely empty (nil), a default action is taken
+instead of no action.")
 
 (defvar mail-abbrevs-loaded nil)
 (defvar mail-mode-map nil)
@@ -100,6 +127,26 @@ If t, it means to insert the contents of the file `~/.signature'.")
 It is inserted before you edit the message,
 so you can edit or delete these lines.")
 
+;; Note: could use /usr/ucb/mail instead of sendmail;
+;; options -t, and -v if not interactive.
+(defvar mail-mailer-swallows-blank-line
+  (if (and (string-match "sparc-sun-sunos\\(\\'\\|[^5]\\)" system-configuration)
+          (file-readable-p "/etc/sendmail.cf")
+          (let ((buffer (get-buffer-create " *temp*")))
+            (unwind-protect
+                (save-excursion
+                  (set-buffer buffer)
+                  (insert-file-contents "/etc/sendmail.cf")
+                  (goto-char (point-min))
+                  (let ((case-fold-search nil))
+                    (re-search-forward "^OR\\>" nil t)))
+              (kill-buffer buffer))))
+      '(looking-at "[ \t]\\|[-a-zA-Z]+:"))
+  "Set this non-nil if the system's mailer runs the header and body together.
+\(This problem exists on Sunos 4 when sendmail is run in remote mode.)
+The value should be an expression to test whether the problem will
+actually occur.")
+
 (defvar mail-mode-syntax-table nil
   "Syntax table used while in mail mode.")
 
@@ -108,6 +155,9 @@ so you can edit or delete these lines.")
      (setq mail-mode-syntax-table (copy-syntax-table text-mode-syntax-table))
      (modify-syntax-entry ?% ". " mail-mode-syntax-table)))
 
+(defvar mail-send-hook nil
+  "Normal hook run before sending mail, in Mail mode.")
+
 (defun mail-setup (to subject in-reply-to cc replybuffer actions)
   (if (eq mail-aliases t)
       (progn
@@ -120,19 +170,19 @@ so you can edit or delete these lines.")
   (insert "To: ")
   (save-excursion
     (if to
-       (progn
+       ;; Here removed code to extract names from within <...>
+       ;; on the assumption that mail-strip-quoted-names
+       ;; has been called and has done so.
+       (let ((fill-prefix "\t")
+             (address-start (point)))
          (insert to "\n")
-         ;;; Here removed code to extract names from within <...>
-         ;;; on the assumption that mail-strip-quoted-names
-         ;;; has been called and has done so.
-         (let ((fill-prefix "\t"))
-           (fill-region (point-min) (point-max))))
+         (fill-region-as-paragraph address-start (point-max)))
       (newline))
     (if cc
-       (let ((opos (point))
-             (fill-prefix "\t"))
-         (insert "CC: " cc "\n")
-         (fill-region-as-paragraph opos (point-max))))
+       (let ((fill-prefix "\t")
+             (address-start (progn (insert "CC: ") (point))))
+         (insert cc "\n")
+         (fill-region-as-paragraph address-start (point-max))))
     (if in-reply-to
        (insert "In-reply-to: " in-reply-to "\n"))
     (insert "Subject: " (or subject "") "\n")
@@ -145,17 +195,18 @@ so you can edit or delete these lines.")
     (if mail-archive-file-name
        (insert "FCC: " mail-archive-file-name "\n"))
     (insert mail-header-separator "\n")
-    ;; Insert the signature.
+    ;; Insert the signature.  But remember the beginning of the message.
+    (if to (setq to (point)))
     (cond ((eq mail-signature t)
           (if (file-exists-p "~/.signature")
               (progn
-                (insert "--\n")
+                (insert "\n\n-- \n")
                 (insert-file-contents "~/.signature"))))
          (mail-signature
           (insert mail-signature)))
     (goto-char (point-max))
     (or (bolp) (newline)))
-  (if to (goto-char (point-max)))
+  (if to (goto-char to))
   (or to subject in-reply-to
       (set-buffer-modified-p nil))
   (run-hooks 'mail-setup-hook))
@@ -168,6 +219,7 @@ C-c C-s  mail-send (send the message)    C-c C-c  mail-send-and-exit
 C-c C-f  move to a header field (and create it if there isn't):
         C-c C-f C-t  move to To:       C-c C-f C-s  move to Subj:
         C-c C-f C-b  move to BCC:      C-c C-f C-c  move to CC:
+        C-c C-f C-f  move to FCC:
 C-c C-t  move to message text.
 C-c C-y  mail-yank-original (insert current message, in Rmail).
 C-c C-q  mail-fill-yanked-message (fill what was yanked).
@@ -192,6 +244,8 @@ C-c C-v  mail-sent-via (add a sent-via field for each To or CC)."
                                   "$\\|^[ \t]*[-_][-_][-_]+$\\|"
                                   paragraph-separate))
   (run-hooks 'text-mode-hook 'mail-mode-hook))
+\f
+;;; Set up keymap.
 
 (if mail-mode-map
     nil
@@ -209,21 +263,90 @@ C-c C-v  mail-sent-via (add a sent-via field for each To or CC)."
   (define-key mail-mode-map "\C-c\C-v" 'mail-sent-via)
   (define-key mail-mode-map "\C-c\C-c" 'mail-send-and-exit)
   (define-key mail-mode-map "\C-c\C-s" 'mail-send))
+
+(define-key mail-mode-map [menu-bar mail]
+  (cons "Mail" (make-sparse-keymap "Mail")))
+
+(define-key mail-mode-map [menu-bar mail fill]
+  '("Fill Citation" . mail-fill-yanked-message))
+
+(define-key mail-mode-map [menu-bar mail yank]
+  '("Cite Original" . mail-yank-original))
+
+(define-key mail-mode-map [menu-bar mail signature]
+  '("Insert Signature" . mail-signature))
+
+(define-key mail-mode-map [menu-bar mail cancel]
+  '("Cancel" . mail-dont-send))
+
+(define-key mail-mode-map [menu-bar mail send-stay]
+  '("Send, Keep Editing" . mail-send))
+
+(define-key mail-mode-map [menu-bar mail send]
+  '("Send Message" . mail-send-and-exit))
+
+(define-key mail-mode-map [menu-bar headers]
+  (cons "Headers" (make-sparse-keymap "Headers")))
+
+(define-key mail-mode-map [menu-bar headers sent-via]
+  '("Sent Via" . mail-sent-via))
+
+(define-key mail-mode-map [menu-bar headers text]
+  '("Text" . mail-text))
+
+(define-key mail-mode-map [menu-bar headers bcc]
+  '("Bcc" . mail-bcc))
+
+(define-key mail-mode-map [menu-bar headers fcc]
+  '("Fcc" . mail-fcc))
+
+(define-key mail-mode-map [menu-bar headers cc]
+  '("Cc" . mail-cc))
+
+(define-key mail-mode-map [menu-bar headers subject]
+  '("Subject" . mail-subject))
+
+(define-key mail-mode-map [menu-bar headers to]
+  '("To" . mail-to))
 \f
 (defun mail-send-and-exit (arg)
   "Send message like `mail-send', then, if no errors, exit from mail buffer.
 Prefix arg means don't delete this window."
   (interactive "P")
   (mail-send)
+  (mail-bury arg))
+
+(defun mail-dont-send (arg)
+  "Don't send the message you have been editing.
+Prefix arg means don't delete this window."
+  (interactive "P")
+  (mail-bury arg))
+
+(defun mail-bury (arg)
+  "Bury this mail buffer."
   (let ((newbuf (other-buffer (current-buffer))))
     (bury-buffer (current-buffer))
-    (if (and (not arg)
+    (if (and (fboundp 'frame-parameters)
+            (cdr (assq 'dedicated (frame-parameters)))
+            (not (null (delq (selected-frame) (visible-frame-list)))))
+       (delete-frame (selected-frame))
+      (let (rmail-flag summary-buffer)
+       (and (not arg)
             (not (one-window-p))
             (save-excursion
               (set-buffer (window-buffer (next-window (selected-window) 'not)))
-              (eq major-mode 'rmail-mode)))
-       (delete-window)
-      (switch-to-buffer newbuf))))
+              (setq rmail-flag (eq major-mode 'rmail-mode))
+              (setq summary-buffer
+                    (and (boundp 'rmail-summary-buffer)
+                         rmail-summary-buffer
+                         (buffer-name rmail-summary-buffer)
+                         (not (get-buffer-window rmail-summary-buffer))
+                         rmail-summary-buffer))))
+       (if rmail-flag
+           ;; If the Rmail buffer has a summary, show that.
+           (if summary-buffer (switch-to-buffer summary-buffer)
+             (delete-window))
+         (switch-to-buffer newbuf))))))
 
 (defun mail-send ()
   "Send the message in the current buffer.
@@ -232,21 +355,27 @@ or error messages, and inform user.
 Otherwise any failure is reported in a message back to
 the user from the mailer."
   (interactive)
-  (if (or (buffer-modified-p)
-          (y-or-n-p "Message already sent; resend? "))
+  (if (if buffer-file-name
+         (y-or-n-p "Send buffer contents as mail message? ")
+       (or (buffer-modified-p)
+           (y-or-n-p "Message already sent; resend? ")))
       (progn
-       (message "Sending...")
        (run-hooks 'mail-send-hook)
+       (message "Sending...")
        (funcall send-mail-function)
        ;; Now perform actions on successful sending.
        (while mail-send-actions
          (condition-case nil
-             (apply (car (car mail-send-actions)) (cdr (car mail-send-actions)))
+             (apply (car (car mail-send-actions))
+                    (cdr (car mail-send-actions)))
            (error))
          (setq mail-send-actions (cdr mail-send-actions)))
-       (set-buffer-modified-p nil)
-       (delete-auto-save-file-if-necessary t)
-       (message "Sending...done"))))
+       (message "Sending...done")
+       ;; If buffer has no file, mark it as unmodified and delete autosave.
+       (if (not buffer-file-name)
+           (progn
+             (set-buffer-modified-p nil)
+             (delete-auto-save-file-if-necessary t))))))
 
 (defun sendmail-send-it ()
   (let ((errbuf (if mail-interactive
@@ -254,6 +383,7 @@ the user from the mailer."
                  0))
        (tembuf (generate-new-buffer " sendmail temp"))
        (case-fold-search nil)
+       resend-to-addresses
        delimline
        (mailbuf (current-buffer)))
     (unwind-protect
@@ -281,26 +411,36 @@ the user from the mailer."
            (replace-match "\n"))
          (let ((case-fold-search t))
            (goto-char (point-min))
-           (if (re-search-forward "^Sender:" delimline t)
-               (error "Sender may not be specified."))
            ;; Find and handle any FCC fields.
            (goto-char (point-min))
            (if (re-search-forward "^FCC:" delimline t)
                (mail-do-fcc delimline))
-           ;; If the From is different than current user, insert Sender.
            (goto-char (point-min))
-           (and (re-search-forward "^From:"  delimline t)
-                (progn
-                  (require 'mail-utils)
-                  (not (string-equal
-                        (mail-strip-quoted-names
-                         (save-restriction
-                           (narrow-to-region (point-min) delimline)
-                           (mail-fetch-field "From")))
-                        (user-login-name))))
-                (progn
-                  (forward-line 1)
-                  (insert "Sender: " (user-login-name) "\n")))
+           (require 'mail-utils)
+           (while (re-search-forward "^Resent-to:" delimline t)
+             (setq resend-to-addresses
+                   (save-restriction
+                     (narrow-to-region (point)
+                                       (save-excursion
+                                         (end-of-line)
+                                         (point)))
+                     (append (mail-parse-comma-list)
+                             resend-to-addresses))))
+;;; Apparently this causes a duplicate Sender.
+;;;        ;; If the From is different than current user, insert Sender.
+;;;        (goto-char (point-min))
+;;;        (and (re-search-forward "^From:"  delimline t)
+;;;             (progn
+;;;               (require 'mail-utils)
+;;;               (not (string-equal
+;;;                     (mail-strip-quoted-names
+;;;                      (save-restriction
+;;;                        (narrow-to-region (point-min) delimline)
+;;;                        (mail-fetch-field "From")))
+;;;                     (user-login-name))))
+;;;             (progn
+;;;               (forward-line 1)
+;;;               (insert "Sender: " (user-login-name) "\n")))
            ;; "S:" is an abbreviation for "Subject:".
            (goto-char (point-min))
            (if (re-search-forward "^S:" delimline t)
@@ -309,6 +449,11 @@ the user from the mailer."
            (goto-char (point-min))
            (if (re-search-forward "^Subject:[ \t]*\n" delimline t)
                (replace-match ""))
+           ;; Insert an extra newline if we need it to work around
+           ;; Sun's bug that swallows newlines.
+           (goto-char (1+ delimline))
+           (if (eval mail-mailer-swallows-blank-line)
+               (newline))
            (if mail-interactive
                (save-excursion
                  (set-buffer errbuf)
@@ -318,8 +463,7 @@ the user from the mailer."
                               (if (boundp 'sendmail-program)
                                   sendmail-program
                                 "/usr/lib/sendmail")
-                              nil errbuf nil
-                              "-oi" "-t")
+                              nil errbuf nil "-oi")
                         ;; Always specify who from,
                         ;; since some systems have broken sendmails.
                         (list "-f" (user-login-name))
@@ -330,7 +474,14 @@ the user from the mailer."
                              (list (concat "-oA" mail-alias-file)))
                         ;; These mean "report errors by mail"
                         ;; and "deliver in background".
-                        (if (null mail-interactive) '("-oem" "-odb"))))
+                        (if (null mail-interactive) '("-oem" "-odb"))
+                        ;; Get the addresses from the message
+                        ;; unless this is a resend.
+                        ;; We must not do that for a resend
+                        ;; because we would find the original addresses.
+                        ;; For a resend, include the specific addresses.
+                        (or resend-to-addresses
+                            '("-t"))))
          (if mail-interactive
              (save-excursion
                (set-buffer errbuf)
@@ -347,7 +498,7 @@ the user from the mailer."
 (defun mail-do-fcc (header-end)
   (let (fcc-list
        (rmailbuf (current-buffer))
-       timezone
+       (time (current-time))
        (tembuf (generate-new-buffer " rmail output"))
        (case-fold-search t))
     (save-excursion
@@ -363,18 +514,14 @@ the user from the mailer."
                       (progn (forward-line 1) (point))))
       (set-buffer tembuf)
       (erase-buffer)
-      (call-process "date" nil t nil)
-      (goto-char (point-min))
-      (re-search-forward 
-        "[0-9] \\([A-Za-z][A-Za-z ]*[A-Za-z]\\)[0-9 ]*$")
-      (setq timezone (buffer-substring (match-beginning 1) (match-end 1)))
-      (erase-buffer)
+      ;; This initial newline is written out if the fcc file already exists.
       (insert "\nFrom " (user-login-name) " "
-             (current-time-string) "\n")
+             (current-time-string time) "\n")
       ;; Insert the time zone before the year.
       (forward-char -1)
       (forward-word -1)
-      (insert timezone " ")
+      (require 'mail-utils)
+      (insert (mail-rfc822-time-zone time) " ")
       (goto-char (point-max))
       (insert-buffer-substring rmailbuf)
       ;; Make sure messages are separated.
@@ -393,7 +540,9 @@ the user from the mailer."
          (if buffer
              ;; File is present in a buffer => append to that buffer.
              (let ((curbuf (current-buffer))
-                   (beg (point-min)) (end (point-max)))
+                   (beg (point-min)) (end (point-max))
+                   (beg2 (save-excursion (goto-char (point-min))
+                                         (forward-line 2) (point))))
                (save-excursion
                  (set-buffer buffer)
                  ;; Keep the end of the accessible portion at the same place
@@ -401,30 +550,38 @@ the user from the mailer."
                  (let ((max (if (/= (1+ (buffer-size)) (point-max))
                                 (point-max))))
                    (unwind-protect
-                       (progn
-                         (narrow-to-region (point-min) (1+ (buffer-size)))
-                         (goto-char (point-max))
-                         (if (eq major-mode 'rmail-mode)
-                             ;; Append as a message to an RMAIL file
-                             (let ((buffer-read-only nil))
-                               ;; This forces RMAIL's message counters to be
-                               ;; recomputed when the next RMAIL operation is
-                               ;; done on the buffer.
-                               ;; See rmail-maybe-set-message-counters.
-                               (setq rmail-total-messages nil)
+                       ;; Code below lifted from rmailout.el
+                       ;; function rmail-output-to-rmail-file:
+                       (let ((buffer-read-only nil)
+                             (msg (and (boundp 'rmail-current-message)
+                                       rmail-current-message)))
+                         ;; If MSG is non-nil, buffer is in RMAIL mode.
+                         (if msg
+                             (progn
+                               (rmail-maybe-set-message-counters)
+                               (widen)
+                               (narrow-to-region (point-max) (point-max))
                                (insert "\C-l\n0, unseen,,\n*** EOOH ***\n"
                                        "From: " (user-login-name) "\n"
-                                       "Date: " (current-time-string) "\n")
-                               (insert-buffer-substring curbuf beg end)
+                                       "Date: " (mail-rfc822-date) "\n")
+                               (insert-buffer-substring curbuf beg2 end)
                                (insert "\n\C-_")
-                               (rmail-set-message-counters))
+                               (goto-char (point-min))
+                               (widen)
+                               (search-backward "\n\^_")
+                               (narrow-to-region (point) (point-max))
+                               (rmail-count-new-messages t)
+                               (rmail-show-message msg)
+                               (setq max nil))
+                           ;; Output file not in rmail mode
+                           ;; => just insert at the end.
+                           (narrow-to-region (point-min) (1+ (buffer-size)))
+                           (goto-char (point-max))
                            (insert-buffer-substring curbuf beg end)))
                      (if max (narrow-to-region (point-min) max))))))
            ;; Else append to the file directly.
            (write-region
-            ;; Include a blank line before if file already exists.
-            (if (file-exists-p (car fcc-list)) (point-min) (1+ (point-min)))
-            (point-max) (car fcc-list) t)))
+            (1+ (point-min)) (point-max) (car fcc-list) t)))
        (setq fcc-list (cdr fcc-list))))
     (kill-buffer tembuf)))
 
@@ -483,13 +640,13 @@ the user from the mailer."
       (progn (mail-position-on-field "to")
             (insert "\nBCC: "))))
 
-(defun mail-fcc ()
+(defun mail-fcc (folder)
   "Add a new FCC field, with file name completion."
-  (interactive)
+  (interactive "FFolder carbon copy: ")
   (expand-abbrev)
   (or (mail-position-on-field "fcc" t) ;Put new field after exiting FCC.
       (mail-position-on-field "to"))
-  (insert "\nFCC: " (read-file-name "Folder carbon copy: ")))
+  (insert "\nFCC: " folder))
 
 (defun mail-position-on-field (field &optional soft)
   (let (end
@@ -506,7 +663,6 @@ the user from the mailer."
          t)
       (or soft
          (progn (goto-char end)
-                (skip-chars-backward "\n")
                 (insert field ": \n")
                 (skip-chars-backward "\n")))
       nil)))
@@ -518,7 +674,8 @@ the user from the mailer."
   (search-forward (concat "\n" mail-header-separator "\n")))
 \f
 (defun mail-signature (atpoint)
-  "Sign letter with contents of `mail-signature-file'."
+  "Sign letter with contents of the file `~/.signature'.
+Prefix arg means put contents at point."
   (interactive "P")
   (save-excursion
     (or atpoint
@@ -527,7 +684,7 @@ the user from the mailer."
     (end-of-line)
     (or atpoint
        (delete-region (point) (point-max)))
-    (insert "\n\n--\n")
+    (insert "\n\n-- \n")
     (insert-file-contents (expand-file-name "~/.signature"))))
 
 (defun mail-fill-yanked-message (&optional justifyp)
@@ -542,6 +699,23 @@ Numeric argument means justify as well."
                                justifyp
                                t)))
 
+(defun mail-indent-citation ()
+  "Modify text just inserted from a message to be cited.
+The inserted text should be the region.
+When this function returns, the region is again around the modified text.
+
+Normally, indent each nonblank line `mail-indentation-spaces' spaces.
+However, if `mail-yank-prefix' is non-nil, insert that prefix on each line."
+  (let ((start (point)))
+    (mail-yank-clear-headers start (mark t))
+    (if (null mail-yank-prefix)
+       (indent-rigidly start (mark t) mail-indentation-spaces)
+      (save-excursion
+       (goto-char start)
+       (while (< (point) (mark t))
+         (insert mail-yank-prefix)
+         (forward-line 1))))))
+
 (defun mail-yank-original (arg)
   "Insert the message being replied to, if any (in rmail).
 Puts point before the text and mark after.
@@ -553,20 +727,26 @@ and don't delete any header fields."
   (interactive "P")
   (if mail-reply-buffer
       (let ((start (point)))
-       (delete-windows-on mail-reply-buffer)
+       ;; If the original message is in another window in the same frame,
+       ;; delete that window to save screen space.
+       ;; t means don't alter other frames.
+       (delete-windows-on mail-reply-buffer t)
        (insert-buffer mail-reply-buffer)
        (if (consp arg)
            nil
-         (mail-yank-clear-headers start (mark))
-         (if (null mail-yank-prefix)
-             (indent-rigidly start (mark)
-                             (if arg (prefix-numeric-value arg) 3))
-           (save-excursion
-             (goto-char start)
-             (while (< (point) (mark))
-               (insert mail-yank-prefix)
-               (forward-line 1)))))
-       (exchange-point-and-mark)
+         (goto-char start)
+         (let ((mail-indentation-spaces (if arg (prefix-numeric-value arg)
+                                          mail-indentation-spaces)))
+           (if mail-citation-hook
+               (run-hooks 'mail-citation-hook)
+             (if mail-yank-hooks
+                 (run-hooks 'mail-yank-hooks)
+               (mail-indent-citation)))))
+       ;; This is like exchange-point-and-mark, but doesn't activate the mark.
+       ;; It is cleaner to avoid activation, even though the command
+       ;; loop would deactivate the mark because we inserted text.
+       (goto-char (prog1 (mark t)
+                    (set-marker (mark-marker) (point) (current-buffer))))
        (if (not (eolp)) (insert ?\n)))))
 
 (defun mail-yank-clear-headers (start end)
@@ -668,9 +848,13 @@ The seventh argument ACTIONS is a list of actions to take
 ;;;          (message "Auto save file for draft message exists; consider M-x mail-recover"))
 ;;;          t))
   (switch-to-buffer "*mail*")
-  (setq default-directory (expand-file-name "~/"))
+  (if (file-exists-p (expand-file-name "~/"))
+      (setq default-directory (expand-file-name "~/")))
   (auto-save-mode auto-save-default)
   (mail-mode)
+  ;; Disconnect the buffer from its visited file
+  ;; (in case the user has actually visited a file *mail*).
+;  (set-visited-file-name nil)
   (let (initialized)
     (and (not noerase)
         (or (not (buffer-modified-p))
@@ -696,7 +880,7 @@ The seventh argument ACTIONS is a list of actions to take
           (let ((buffer-read-only nil))
             (erase-buffer)
             (insert-file-contents file-name nil)))
-         (t (error "mail-recover cancelled.")))))
+         (t (error "mail-recover cancelled")))))
 
 ;;;###autoload
 (defun mail-other-window (&optional noerase to subject in-reply-to cc replybuffer sendactions)
@@ -714,16 +898,11 @@ The seventh argument ACTIONS is a list of actions to take
     (pop-to-buffer "*mail*"))
   (mail noerase to subject in-reply-to cc replybuffer sendactions))
 
-
-;;;###autoload
-(define-key ctl-x-map "m" 'mail)
-
-;;;###autoload
-(define-key ctl-x-4-map "m" 'mail-other-window)
-
-;;;###autoload
-(define-key ctl-x-5-map "m" 'mail-other-frame)
-
+;;; Do not execute these when sendmail.el is loaded,
+;;; only in loaddefs.el.
+;;;###autoload (define-key ctl-x-map "m" 'mail)
+;;;###autoload (define-key ctl-x-4-map "m" 'mail-other-window)
+;;;###autoload (define-key ctl-x-5-map "m" 'mail-other-frame)
 
 ;;; Do not add anything but external entries on this page.