1 ;;; message.el --- composing mail and news messages
2 ;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
3 ;; Free Software Foundation, Inc.
5 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
6 ;; Keywords: mail, news
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
27 ;; This mode provides mail-sending facilities from within Emacs. It
28 ;; consists mainly of large chunks of code from the sendmail.el,
29 ;; gnus-msg.el and rnewspost.el files.
35 (defvar gnus-list-identifiers)) ; gnus-sum is required where necessary
39 ;; This is apparently necessary even though things are autoloaded.
40 ;; Because we dynamically bind mail-abbrev-mode-regexp, we'd better
41 ;; require mailabbrev here.
42 (if (featurep 'xemacs)
43 (require 'mail-abbrevs)
44 (require 'mailabbrev))
49 (autoload 'sha1 "sha1-el"))
51 (defgroup message '((user-mail-address custom-variable)
52 (user-full-name custom-variable))
53 "Mail and news message composing."
54 :link '(custom-manual "(message)Top")
58 (put 'user-mail-address 'custom-type 'string)
59 (put 'user-full-name 'custom-type 'string)
61 (defgroup message-various nil
62 "Various Message Variables"
63 :link '(custom-manual "(message)Various Message Variables")
66 (defgroup message-buffers nil
68 :link '(custom-manual "(message)Message Buffers")
71 (defgroup message-sending nil
73 :link '(custom-manual "(message)Sending Variables")
76 (defgroup message-interface nil
78 :link '(custom-manual "(message)Interface")
81 (defgroup message-forwarding nil
83 :link '(custom-manual "(message)Forwarding")
84 :group 'message-interface)
86 (defgroup message-insertion nil
88 :link '(custom-manual "(message)Insertion")
91 (defgroup message-headers nil
93 :link '(custom-manual "(message)Message Headers")
96 (defgroup message-news nil
97 "Composing News Messages"
100 (defgroup message-mail nil
101 "Composing Mail Messages"
104 (defgroup message-faces nil
105 "Faces used for message composing."
109 (defcustom message-directory "~/Mail/"
110 "*Directory from which all other mail file variables are derived."
111 :group 'message-various
114 (defcustom message-max-buffers 10
115 "*How many buffers to keep before starting to kill them off."
116 :group 'message-buffers
119 (defcustom message-send-rename-function nil
120 "Function called to rename the buffer after sending it."
121 :group 'message-buffers
122 :type '(choice function (const nil)))
124 (defcustom message-fcc-handler-function 'message-output
125 "*A function called to save outgoing articles.
126 This function will be called with the name of the file to store the
127 article in. The default function is `message-output' which saves in Unix
129 :type '(radio (function-item message-output)
130 (function :tag "Other"))
131 :group 'message-sending)
133 (defcustom message-fcc-externalize-attachments nil
134 "If non-nil, attachments are included as external parts in Fcc copies."
136 :group 'message-sending)
138 (defcustom message-courtesy-message
139 "The following message is a courtesy copy of an article\nthat has been posted to %s as well.\n\n"
140 "*This is inserted at the start of a mailed copy of a posted message.
141 If the string contains the format spec \"%s\", the Newsgroups
142 the article has been posted to will be inserted there.
143 If this variable is nil, no such courtesy message will be added."
144 :group 'message-sending
147 (defcustom message-ignored-bounced-headers "^\\(Received\\|Return-Path\\):"
148 "*Regexp that matches headers to be removed in resent bounced mail."
149 :group 'message-interface
153 (defcustom message-from-style 'default
154 "*Specifies how \"From\" headers look.
156 If nil, they contain just the return address like:
158 If `parens', they look like:
159 king@grassland.com (Elvis Parsley)
160 If `angles', they look like:
161 Elvis Parsley <king@grassland.com>
163 Otherwise, most addresses look like `angles', but they look like
164 `parens' if `angles' would need quoting and `parens' would not."
165 :type '(choice (const :tag "simple" nil)
169 :group 'message-headers)
171 (defcustom message-insert-canlock t
172 "Whether to insert a Cancel-Lock header in news postings."
174 :group 'message-headers
177 (defcustom message-syntax-checks
178 (if message-insert-canlock '((sender . disabled)) nil)
179 ;; Guess this one shouldn't be easy to customize...
180 "*Controls what syntax checks should not be performed on outgoing posts.
181 To disable checking of long signatures, for instance, add
182 `(signature . disabled)' to this list.
184 Don't touch this variable unless you really know what you're doing.
186 Checks include `subject-cmsg', `multiple-headers', `sendsys',
187 `message-id', `from', `long-lines', `control-chars', `size',
188 `new-text', `quoting-style', `redirected-followup', `signature',
189 `approved', `sender', `empty', `empty-headers', `message-id', `from',
190 `subject', `shorten-followup-to', `existing-newsgroups',
191 `buffer-file-name', `unchanged', `newsgroups', `reply-to',
192 'continuation-headers', and `long-header-lines'."
194 :type '(repeat sexp)) ; Fixme: improve this
196 (defcustom message-required-headers '((optional . References)
198 "*Headers to be generated or prompted for when sending a message.
199 Also see `message-required-news-headers' and
200 `message-required-mail-headers'."
202 :group 'message-headers
203 :type '(repeat sexp))
205 (defcustom message-draft-headers '(References From)
206 "*Headers to be generated when saving a draft message."
208 :group 'message-headers
209 :type '(repeat sexp))
211 (defcustom message-required-news-headers
212 '(From Newsgroups Subject Date Message-ID
213 (optional . Organization)
214 (optional . User-Agent))
215 "*Headers to be generated or prompted for when posting an article.
216 RFC977 and RFC1036 require From, Date, Newsgroups, Subject,
217 Message-ID. Organization, Lines, In-Reply-To, Expires, and
218 User-Agent are optional. If don't you want message to insert some
219 header, remove it from this list."
221 :group 'message-headers
222 :type '(repeat sexp))
224 (defcustom message-required-mail-headers
225 '(From Subject Date (optional . In-Reply-To) Message-ID
226 (optional . User-Agent))
227 "*Headers to be generated or prompted for when mailing a message.
228 It is recommended that From, Date, To, Subject and Message-ID be
229 included. Organization and User-Agent are optional."
231 :group 'message-headers
232 :type '(repeat sexp))
234 (defcustom message-deletable-headers '(Message-ID Date Lines)
235 "Headers to be deleted if they already exist and were generated by message previously."
236 :group 'message-headers
239 (defcustom message-ignored-news-headers
240 "^NNTP-Posting-Host:\\|^Xref:\\|^[BGF]cc:\\|^Resent-Fcc:\\|^X-Draft-From:\\|^X-Gnus-Agent-Meta-Information:"
241 "*Regexp of headers to be removed unconditionally before posting."
243 :group 'message-headers
246 (defcustom message-ignored-mail-headers
247 "^[GF]cc:\\|^Resent-Fcc:\\|^Xref:\\|^X-Draft-From:\\|^X-Gnus-Agent-Meta-Information:"
248 "*Regexp of headers to be removed unconditionally before mailing."
250 :group 'message-headers
253 (defcustom message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|^X-Trace:\\|^X-Complaints-To:\\|Return-Path:\\|^Supersedes:\\|^NNTP-Posting-Date:\\|^X-Trace:\\|^X-Complaints-To:\\|^Cancel-Lock:\\|^Cancel-Key:\\|^X-Hashcash:"
254 "*Header lines matching this regexp will be deleted before posting.
255 It's best to delete old Path and Date headers before posting to avoid
257 :group 'message-interface
260 (defcustom message-subject-re-regexp
261 "^[ \t]*\\([Rr][Ee]\\(\\[[0-9]*\\]\\)*:[ \t]*\\)*[ \t]*"
262 "*Regexp matching \"Re: \" in the subject line."
263 :group 'message-various
266 ;;; Start of variables adopted from `message-utils.el'.
268 (defcustom message-subject-trailing-was-query 'ask
269 ;; should it default to nil or ask?
270 "*What to do with trailing \"(was: <old subject>)\" in subject lines.
271 If nil, leave the subject unchanged. If it is the symbol `ask', query
272 the user what do do. In this case, the subject is matched against
273 `message-subject-trailing-was-ask-regexp'. If
274 `message-subject-trailing-was-query' is t, always strip the trailing
275 old subject. In this case, `message-subject-trailing-was-regexp' is
277 :type '(choice (const :tag "never" nil)
278 (const :tag "always strip" t)
280 :group 'message-various)
282 (defcustom message-subject-trailing-was-ask-regexp
283 "[ \t]*\\([[(]+[Ww][Aa][Ss][ \t]*.*[\])]+\\)"
284 "*Regexp matching \"(was: <old subject>)\" in the subject line.
286 The function `message-strip-subject-trailing-was' uses this regexp if
287 `message-subject-trailing-was-query' is set to the symbol `ask'. If
288 the variable is t instead of `ask', use
289 `message-subject-trailing-was-regexp' instead.
291 It is okay to create some false positives here, as the user is asked."
292 :group 'message-various
295 (defcustom message-subject-trailing-was-regexp
296 "[ \t]*\\((*[Ww][Aa][Ss]:[ \t]*.*)\\)"
297 "*Regexp matching \"(was: <old subject>)\" in the subject line.
299 If `message-subject-trailing-was-query' is set to t, the subject is
300 matched against `message-subject-trailing-was-regexp' in
301 `message-strip-subject-trailing-was'. You should use a regexp creating very
302 few false positives here."
303 :group 'message-various
306 ;;; marking inserted text
309 (defcustom message-mark-insert-begin
310 "--8<---------------cut here---------------start------------->8---\n"
311 "How to mark the beginning of some inserted text."
313 :group 'message-various)
316 (defcustom message-mark-insert-end
317 "--8<---------------cut here---------------end--------------->8---\n"
318 "How to mark the end of some inserted text."
320 :group 'message-various)
323 (defcustom message-archive-header
324 "X-No-Archive: Yes\n"
325 "Header to insert when you don't want your article to be archived.
326 Archives \(such as groups.googgle.com\) respect this header."
328 :group 'message-various)
331 (defcustom message-archive-note
332 "X-No-Archive: Yes - save http://groups.google.com/"
333 "Note to insert why you wouldn't want this posting archived.
334 If nil, don't insert any text in the body."
336 :group 'message-various)
338 ;;; Crossposts and Followups
339 ;; inspired by JoH-followup-to by Jochem Huhman <joh at gmx.de>
340 ;; new suggestions by R. Weikusat <rw at another.de>
342 (defvar message-cross-post-old-target nil
343 "Old target for cross-posts or follow-ups.")
344 (make-variable-buffer-local 'message-cross-post-old-target)
347 (defcustom message-cross-post-default t
348 "When non-nil `message-cross-post-followup-to' will perform a crosspost.
349 If nil, `message-cross-post-followup-to' will only do a followup. Note that
350 you can explicitly override this setting by calling
351 `message-cross-post-followup-to' with a prefix."
353 :group 'message-various)
356 (defcustom message-cross-post-note
357 "Crosspost & Followup-To: "
358 "Note to insert before signature to notify of cross-post and follow-up."
360 :group 'message-various)
363 (defcustom message-followup-to-note
365 "Note to insert before signature to notify of follow-up only."
367 :group 'message-various)
370 (defcustom message-cross-post-note-function
371 'message-cross-post-insert-note
372 "Function to use to insert note about Crosspost or Followup-To.
373 The function will be called with four arguments. The function should not only
374 insert a note, but also ensure old notes are deleted. See the documentation
375 for `message-cross-post-insert-note'."
377 :group 'message-various)
379 ;;; End of variables adopted from `message-utils.el'.
382 (defcustom message-signature-separator "^-- *$"
383 "Regexp matching the signature separator."
385 :group 'message-various)
387 (defcustom message-elide-ellipsis "\n[...]\n\n"
388 "*The string which is inserted for elided text."
390 :group 'message-various)
392 (defcustom message-interactive t
393 "Non-nil means when sending a message wait for and display errors.
394 nil means let mailer mail back a message to report errors."
395 :group 'message-sending
399 (defcustom message-generate-new-buffers 'unique
400 "*Non-nil means create a new message buffer whenever `message-setup' is called.
401 If this is a function, call that function with three parameters: The type,
402 the to address and the group name. (Any of these may be nil.) The function
403 should return the new buffer name."
404 :group 'message-buffers
405 :type '(choice (const :tag "off" nil)
406 (const :tag "unique" unique)
407 (const :tag "unsent" unsent)
410 (defcustom message-kill-buffer-on-exit nil
411 "*Non-nil means that the message buffer will be killed after sending a message."
412 :group 'message-buffers
416 (defvar gnus-local-organization))
417 (defcustom message-user-organization
418 (or (and (boundp 'gnus-local-organization)
419 (stringp gnus-local-organization)
420 gnus-local-organization)
421 (getenv "ORGANIZATION")
423 "*String to be used as an Organization header.
424 If t, use `message-user-organization-file'."
425 :group 'message-headers
426 :type '(choice string
427 (const :tag "consult file" t)))
430 (defcustom message-user-organization-file "/usr/lib/news/organization"
431 "*Local news organization file."
433 :group 'message-headers)
435 (defcustom message-make-forward-subject-function
436 'message-forward-subject-name-subject
437 "*List of functions called to generate subject headers for forwarded messages.
438 The subject generated by the previous function is passed into each
441 The provided functions are:
443 * `message-forward-subject-author-subject' (Source of article (author or
444 newsgroup)), in brackets followed by the subject
445 * `message-forward-subject-name-subject' (Source of article (name of author
446 or newsgroup)), in brackets followed by the subject
447 * `message-forward-subject-fwd' (Subject of article with 'Fwd:' prepended
449 :group 'message-forwarding
450 :type '(radio (function-item message-forward-subject-author-subject)
451 (function-item message-forward-subject-fwd)
452 (repeat :tag "List of functions" function)))
454 (defcustom message-forward-as-mime t
455 "*If non-nil, forward messages as an inline/rfc822 MIME section. Otherwise, directly inline the old message in the forwarded message."
457 :group 'message-forwarding
460 (defcustom message-forward-show-mml t
461 "*If non-nil, forward messages are shown as mml. Otherwise, forward messages are unchanged."
463 :group 'message-forwarding
466 (defcustom message-forward-before-signature t
467 "*If non-nil, put forwarded message before signature, else after."
468 :group 'message-forwarding
471 (defcustom message-wash-forwarded-subjects nil
472 "*If non-nil, try to remove as much old cruft as possible from the subject of messages before generating the new subject of a forward."
473 :group 'message-forwarding
476 (defcustom message-ignored-resent-headers "^Return-receipt\\|^X-Gnus\\|^Gnus-Warning:\\|^>?From "
477 "*All headers that match this regexp will be deleted when resending a message."
478 :group 'message-interface
481 (defcustom message-forward-ignored-headers "^Content-Transfer-Encoding:\\|^X-Gnus"
482 "*All headers that match this regexp will be deleted when forwarding a message."
484 :group 'message-forwarding
485 :type '(choice (const :tag "None" nil)
488 (defcustom message-ignored-cited-headers "."
489 "*Delete these headers from the messages you yank."
490 :group 'message-insertion
493 (defcustom message-cite-prefix-regexp
494 (if (string-match "[[:digit:]]" "1") ;; support POSIX?
495 "\\([ \t]*[-_.[:word:]]+>+\\|[ \t]*[]>|}+]\\)+"
496 ;; ?-, ?_ or ?. MUST NOT be in syntax entry w.
497 (let ((old-table (syntax-table))
498 non-word-constituents)
499 (set-syntax-table text-mode-syntax-table)
500 (setq non-word-constituents
502 (if (string-match "\\w" "-") "" "-")
503 (if (string-match "\\w" "_") "" "_")
504 (if (string-match "\\w" ".") "" ".")))
505 (set-syntax-table old-table)
506 (if (equal non-word-constituents "")
507 "\\([ \t]*\\(\\w\\)+>+\\|[ \t]*[]>|}+]\\)+"
508 (concat "\\([ \t]*\\(\\w\\|["
509 non-word-constituents
510 "]\\)+>+\\|[ \t]*[]>|}+]\\)+"))))
511 "*Regexp matching the longest possible citation prefix on a line."
512 :group 'message-insertion
515 (defcustom message-cancel-message "I am canceling my own article.\n"
516 "Message to be inserted in the cancel message."
517 :group 'message-interface
520 ;; Useful to set in site-init.el
522 (defcustom message-send-mail-function 'message-send-mail-with-sendmail
523 "Function to call to send the current buffer as mail.
524 The headers should be delimited by a line whose contents match the
525 variable `mail-header-separator'.
527 Valid values include `message-send-mail-with-sendmail' (the default),
528 `message-send-mail-with-mh', `message-send-mail-with-qmail',
529 `message-smtpmail-send-it', `smtpmail-send-it' and `feedmail-send-it'.
531 See also `send-mail-function'."
532 :type '(radio (function-item message-send-mail-with-sendmail)
533 (function-item message-send-mail-with-mh)
534 (function-item message-send-mail-with-qmail)
535 (function-item message-smtpmail-send-it)
536 (function-item smtpmail-send-it)
537 (function-item feedmail-send-it)
538 (function :tag "Other"))
539 :group 'message-sending
540 :group 'message-mail)
542 (defcustom message-send-news-function 'message-send-news
543 "Function to call to send the current buffer as news.
544 The headers should be delimited by a line whose contents match the
545 variable `mail-header-separator'."
546 :group 'message-sending
550 (defcustom message-reply-to-function nil
551 "If non-nil, function that should return a list of headers.
552 This function should pick out addresses from the To, Cc, and From headers
553 and respond with new To and Cc headers."
554 :group 'message-interface
555 :type '(choice function (const nil)))
557 (defcustom message-wide-reply-to-function nil
558 "If non-nil, function that should return a list of headers.
559 This function should pick out addresses from the To, Cc, and From headers
560 and respond with new To and Cc headers."
561 :group 'message-interface
562 :type '(choice function (const nil)))
564 (defcustom message-followup-to-function nil
565 "If non-nil, function