1 ;;; smtpmail.el --- simple SMTP protocol (RFC 821) for sending mail
3 ;; Copyright (C) 1995, 1996 Free Software Foundation, Inc.
5 ;; Author: Tomoji Kagatani <kagatani@rbc.ncl.omron.co.jp>
6 ;; Maintainer: Brian D. Carlstrom <bdc@ai.mit.edu>
7 ;; ESMTP support: Simon Leinen <simon@switch.ch>
10 ;; This file is part of GNU Emacs.
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
29 ;; Send Mail to smtp host from smtpmail temp buffer.
31 ;; Please add these lines in your .emacs(_emacs).
33 ;;(setq send-mail-function 'smtpmail-send-it)
34 ;;(setq smtp-default-server "YOUR SMTP HOST")
35 ;;(setq smtp-service "smtp")
36 ;;(setq smtp-local-domain "YOUR DOMAIN NAME")
37 ;;(setq smtp-debug-info t)
38 ;;(autoload 'smtpmail-send-it "smtpmail")
39 ;;(setq user-full-name "YOUR NAME HERE")
41 ;; To queue mail, set smtpmail-queue-mail to t and use
42 ;; smtpmail-send-queued-mail to send.
53 (defcustom smtpmail-queue-mail nil
54 "*Specify if mail is queued (if t) or sent immediately (if nil).
55 If queued, it is stored in the directory `smtpmail-queue-dir'
56 and sent with `smtpmail-send-queued-mail'."
60 (defcustom smtpmail-queue-dir "~/Mail/queued-mail/"
61 "*Directory where `smtpmail.el' stores queued mail."
65 (defvar smtpmail-queue-index-file "index"
66 "File name of queued mail index,
67 This is relative to `smtpmail-queue-dir'.")
69 (defvar smtpmail-queue-index (concat smtpmail-queue-dir
70 smtpmail-queue-index-file))
72 (defvar smtpmail-recipient-address-list nil)
80 (defun smtpmail-send-it ()
82 (let ((errbuf (if mail-interactive
83 (generate-new-buffer " smtpmail errors")
85 (tembuf (generate-new-buffer " smtpmail temp"))
86 (case-fold-search nil)
89 (mailbuf (current-buffer)))
94 (insert-buffer-substring mailbuf)
95 (goto-char (point-max))
96 ;; require one newline at the end.
97 (or (= (preceding-char) ?\n)
99 ;; Change header-delimiter to be what sendmail expects.
100 (goto-char (point-min))
102 (concat "^" (regexp-quote mail-header-separator) "\n"))
105 (setq delimline (point-marker))
106 ;; (sendmail-synch-aliases)
108 (expand-mail-aliases (point-min) delimline))
109 (goto-char (point-min))
110 ;; ignore any blank lines in the header
111 (while (and (re-search-forward "\n\n\n*" delimline t)
112 (< (point) delimline))
113 (replace-match "\n"))
114 (let ((case-fold-search t))
115 (goto-char (point-min))
116 (goto-char (point-min))
117 (while (re-search-forward "^Resent-to:" delimline t)
118 (setq resend-to-addresses
120 (narrow-to-region (point)
124 (append (mail-parse-comma-list)
125 resend-to-addresses))))
126 ;;; Apparently this causes a duplicate Sender.
127 ;;; ;; If the From is different than current user, insert Sender.
128 ;;; (goto-char (point-min))
129 ;;; (and (re-search-forward "^From:" delimline t)
131 ;;; (require 'mail-utils)
132 ;;; (not (string-equal
133 ;;; (mail-strip-quoted-names
134 ;;; (save-restriction
135 ;;; (narrow-to-region (point-min) delimline)
136 ;;; (mail-fetch-field "From")))
137 ;;; (user-login-name))))
140 ;;; (insert "Sender: " (user-login-name) "\n")))
141 ;; Don't send out a blank subject line
142 (goto-char (point-min))
143 (if (re-search-forward "^Subject:[ \t]*\n" delimline t)
145 ;; Put the "From:" field in unless for some odd reason
146 ;; they put one in themselves.
147 (goto-char (point-min))
148 (if (not (re-search-forward "^From:" delimline t))
149 (let* ((login user-mail-address)
150 (fullname (user-full-name)))
151 (cond ((eq mail-from-style 'angles)
152 (insert "From: " fullname)
153 (let ((fullname-start (+ (point-min) 6))
154 (fullname-end (point-marker)))
155 (goto-char fullname-start)
156 ;; Look for a character that cannot appear unquoted
157 ;; according to RFC 822.
158 (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]"
161 ;; Quote fullname, escaping specials.
162 (goto-char fullname-start)
164 (while (re-search-forward "[\"\\]"
166 (replace-match "\\\\\\&" t))
168 (insert " <" login ">\n"))
169 ((eq mail-from-style 'parens)
170 (insert "From: " login " (")
171 (let ((fullname-start (point)))
173 (let ((fullname-end (point-marker)))
174 (goto-char fullname-start)
175 ;; RFC 822 says \ and nonmatching parentheses
176 ;; must be escaped in comments.
177 ;; Escape every instance of ()\ ...
178 (while (re-search-forward "[()\\]" fullname-end 1)
179 (replace-match "\\\\\\&" t))
180 ;; ... then undo escaping of matching parentheses,
181 ;; including matching nested parentheses.
182 (goto-char fullname-start)
183 (while (re-search-forward
184 "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
186 (replace-match "\\1(\\3)" t)
187 (goto-char fullname-start))))
189 ((null mail-from-style)
190 (insert "From: " login "\n")))))
191 ;; Insert an extra newline if we need it to work around
192 ;; Sun's bug that swallows newlines.
193 (goto-char (1+ delimline))
194 (if (eval mail-mailer-swallows-blank-line)
196 ;; Find and handle any FCC fields.
197 (goto-char (point-min))
198 (if (re-search-forward "^FCC:" delimline t)
199 (mail-do-fcc delimline))
207 (setq smtpmail-recipient-address-list
208 (or resend-to-addresses
209 (smtp-deduce-address-list tembuf (point-min) delimline)))
211 (smtpmail-do-bcc delimline)
213 (if (not smtpmail-queue-mail)
214 (if smtpmail-recipient-address-list
215 (if (not (smtp-via-smtp user-mail-address
216 smtpmail-recipient-address-list
218 (error "Sending failed; SMTP protocol error"))
219 (error "Sending failed; no recipients"))
220 (let* ((file-data (concat
223 "%02y%02m%02d-%02H%02M%02S")))
224 (file-elisp (concat file-data ".el"))
225 (buffer-data (create-file-buffer file-data))
226 (buffer-elisp (create-file-buffer file-elisp))
227 (buffer-scratch "*queue-mail*"))
229 (set-buffer buffer-data)
231 (insert-buffer tembuf)
232 (write-file file-data)
233 (set-buffer buffer-elisp)
236 "(setq smtpmail-recipient-address-list '"
237 (prin1-to-string smtpmail-recipient-address-list)
239 (write-file file-elisp)
240 (set-buffer (generate-new-buffer buffer-scratch))
241 (insert (concat file-data "\n"))
242 (append-to-file (point-min)
244 smtpmail-queue-index)
246 (kill-buffer buffer-scratch)
247 (kill-buffer buffer-data)
248 (kill-buffer buffer-elisp))))
251 (kill-buffer errbuf)))))
253 (defun smtpmail-send-queued-mail ()
254 "Send mail that was queued as a result of setting `smtpmail-queue-mail'."
256 ;;; Get index, get first mail, send it, get second mail, etc...
257 (let ((buffer-index (find-file-noselect smtpmail-queue-index))
261 (set-buffer buffer-index)
262 (beginning-of-buffer)
264 (setq file-msg (buffer-substring (point) (save-excursion
268 (setq tembuf (find-file-noselect file-msg))
269 (if smtpmail-recipient-address-list
270 (if (not (smtp-via-smtp user-mail-address
271 smtpmail-recipient-address-list tembuf))
272 (error "Sending failed; SMTP protocol error"))
273 (error "Sending failed; no recipients"))
274 (delete-file file-msg)
275 (delete-file (concat file-msg ".el"))
278 (set-buffer buffer-index)
279 (save-buffer smtpmail-queue-index)
280 (kill-buffer buffer-index)
284 (defun smtpmail-do-bcc (header-end)
285 "Delete BCC: and their continuation lines from the header area.
286 There may be multiple BCC: lines, and each may have arbitrarily
287 many continuation lines."
288 (let ((case-fold-search t))
290 (goto-char (point-min))
291 ;; iterate over all BCC: lines
292 (while (re-search-forward "^BCC:" header-end t)
293 (delete-region (match-beginning 0) (progn (forward-line 1) (point)))
294 ;; get rid of any continuation lines
295 (while (and (looking-at "^[ \t].*\n") (< (point) header-end))
307 ;;; smtpmail.el ends here