unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
@ 2023-05-05 13:13 Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-05 18:57 ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-05 13:13 UTC (permalink / raw)
  To: 63311

[-- Attachment #1: Type: text/plain, Size: 606 bytes --]


Hi,

I'm trying to make sending mail over SMTP asynchronous.  For this, I'm
working on 'smtpmail-send-it'… but I think that that function does too
much and is hard to reason about.

This patch just splits 'smtpmail-send-it' work into three functions:
prepare a mail and queue it or send it.  There should be no change in
functionality (it is mostly code refactoring).  I've tested it a bit
with sending and queueing and this seems to work correctly but this
needs way more eyes and tests.

BTW, does anyone know the purpose of 'errbuf': I see it is created then
erased and then killed?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-smtpmail-send-it-split.patch --]
[-- Type: text/x-patch, Size: 18239 bytes --]

From 6481038443deae8bf4e309a641f5ce77717be712 Mon Sep 17 00:00:00 2001
From: Manuel Giraud <manuel@ledu-giraud.fr>
Date: Fri, 5 May 2023 14:35:01 +0200
Subject: [PATCH] smtpmail-send-it split

* lisp/mail/smtpmail.el (smtpmail-prepare-mail): New function that
prepares the mail with current buffer content.
(smtpmail-queue-mail): New function to queue a mail (prepared by
'smtpmail-prepare-mail').
(smtpmail-send-mail): New function to send a mail (prepared by
'smtpmail-send-mail').
(smtpmail-send-it): Use all three previous functions.
---
 lisp/mail/smtpmail.el | 407 +++++++++++++++++++++---------------------
 1 file changed, 206 insertions(+), 201 deletions(-)

diff --git a/lisp/mail/smtpmail.el b/lisp/mail/smtpmail.el
index 78688d170cc..7c61ca29de6 100644
--- a/lisp/mail/smtpmail.el
+++ b/lisp/mail/smtpmail.el
@@ -205,214 +205,219 @@ smtpmail-mail-address
   "Value to use for envelope-from address for mail from ambient buffer.")
 
 ;;; Functions
+(defun smtpmail-prepare-mail (tembuf errbuf smtpmail-code-conv-from)
+    (let ((case-fold-search nil)
+	  delimline
+	  (mailbuf (current-buffer))
+         ;; Examine this variable now, so that
+	 ;; local binding in the mail buffer will take effect.
+	 (smtpmail-mail-address
+          (save-restriction
+            ;; Only look at the headers when fetching the
+            ;; envelope address.
+            (message-narrow-to-headers)
+            (or (and mail-specify-envelope-from (mail-envelope-from))
+                (let ((from (mail-fetch-field "from")))
+	          (and from
+		       (cadr (mail-extract-address-components from))))
+	        (smtpmail-user-mail-address)))))
+    (with-current-buffer tembuf
+      (erase-buffer)
+      ;; Use the same `buffer-file-coding-system' as in the mail
+      ;; buffer, otherwise any `write-region' invocations (e.g., in
+      ;; mail-do-fcc below) will annoy with asking for a suitable
+      ;; encoding.
+      (set-buffer-file-coding-system smtpmail-code-conv-from nil t)
+      (insert-buffer-substring mailbuf)
+      (goto-char (point-max))
+      ;; require one newline at the end.
+      (or (= (preceding-char) ?\n)
+	  (insert ?\n))
+      ;; Change header-delimiter to be what sendmail expects.
+      (mail-sendmail-undelimit-header)
+      (setq delimline (point-marker))
+      (if mail-aliases
+	  (expand-mail-aliases (point-min) delimline))
+      (goto-char (point-min))
+      ;; ignore any blank lines in the header
+      (while (and (re-search-forward "\n\n\n*" delimline t)
+		  (< (point) delimline))
+	(replace-match "\n"))
+      (let ((case-fold-search t))
+	;; We used to process Resent-... headers here,
+	;; but it was not done properly, and the job
+	;; is done correctly in `smtpmail-deduce-address-list'.
+	;; Don't send out a blank subject line
+	(goto-char (point-min))
+	(if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t)
+	    (replace-match "")
+	  ;; This one matches a Subject just before the header delimiter.
+	  (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t)
+		   (= (match-end 0) delimline))
+	      (replace-match "")))
+	;; Put the "From:" field in unless for some odd reason
+	;; they put one in themselves.
+	(goto-char (point-min))
+	(if (not (re-search-forward "^From:" delimline t))
+	    (let* ((login smtpmail-mail-address)
+		   (fullname (user-full-name)))
+	      (cond ((eq mail-from-style 'angles)
+		     (insert "From: " fullname)
+		     (let ((fullname-start (+ (point-min) 6))
+			   (fullname-end (point-marker)))
+		       (goto-char fullname-start)
+		       ;; Look for a character that cannot appear unquoted
+		       ;; according to RFC 822 or its successors.
+		       (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]"
+					      fullname-end 1)
+			   (progn
+			     ;; Quote fullname, escaping specials.
+			     (goto-char fullname-start)
+			     (insert "\"")
+			     (while (re-search-forward "[\"\\]"
+						       fullname-end 1)
+			       (replace-match "\\\\\\&" t))
+			     (insert "\""))))
+		     (insert " <" login ">\n"))
+		    ((eq mail-from-style 'parens)
+		     (insert "From: " login " (")
+		     (let ((fullname-start (point)))
+		       (insert fullname)
+		       (let ((fullname-end (point-marker)))
+			 (goto-char fullname-start)
+			 ;; RFC 822 and its successors say \ and
+			 ;; nonmatching parentheses must be
+			 ;; escaped in comments.
+			 ;; Escape every instance of ()\ ...
+			 (while (re-search-forward "[()\\]" fullname-end 1)
+			   (replace-match "\\\\\\&" t))
+			 ;; ... then undo escaping of matching parentheses,
+			 ;; including matching nested parentheses.
+			 (goto-char fullname-start)
+			 (while (re-search-forward
+				 "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
+				 fullname-end 1)
+			   (replace-match "\\1(\\3)" t)
+			   (goto-char fullname-start))))
+		     (insert ")\n"))
+		    ((null mail-from-style)
+		     (insert "From: " login "\n")))))
+	;; Insert a `Message-Id:' field if there isn't one yet.
+	(goto-char (point-min))
+	(unless (re-search-forward "^Message-Id:" delimline t)
+	  (insert "Message-Id: " (message-make-message-id) "\n"))
+	;; Insert a `Date:' field if there isn't one yet.
+	(goto-char (point-min))
+	(unless (re-search-forward "^Date:" delimline t)
+	  (insert "Date: " (message-make-date) "\n"))
+	;; Possibly add a MIME header for the current coding system
+	(let (charset)
+	  (goto-char (point-min))
+	  (and (eq mail-send-nonascii 'mime)
+	       (not (re-search-forward "^MIME-version:" delimline t))
+	       (progn (skip-chars-forward "\0-\177")
+		      (/= (point) (point-max)))
+	       smtpmail-code-conv-from
+	       (setq charset
+		     (coding-system-get smtpmail-code-conv-from
+					'mime-charset))
+	       (goto-char delimline)
+	       (insert "MIME-version: 1.0\n"
+		       "Content-type: text/plain; charset="
+		       (symbol-name charset)
+		       "\nContent-Transfer-Encoding: 8bit\n")))
+	;; Insert an extra newline if we need it to work around
+	;; Sun's bug that swallows newlines.
+	(goto-char (1+ delimline))
+	;; Find and handle any Fcc fields.
+	(goto-char (point-min))
+	(if (re-search-forward "^Fcc:" delimline t)
+	    ;; Force `mail-do-fcc' to use the encoding of the mail
+	    ;; buffer to encode outgoing messages on Fcc files.
+	    (let ((coding-system-for-write
+		   ;; mbox files must have Unix EOLs.
+		   (coding-system-change-eol-conversion
+		    smtpmail-code-conv-from 'unix)))
+	      (mail-do-fcc delimline)))
+	(if mail-interactive
+	    (with-current-buffer errbuf
+	      (erase-buffer))))
+      ;; Encode the header according to RFC2047.
+      (mail-encode-header (point-min) delimline)
+      ;;
+      (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*"))
+      (setq smtpmail-recipient-address-list
+            (smtpmail-deduce-address-list tembuf (point-min) delimline))
+      (kill-buffer smtpmail-address-buffer)
+
+      (smtpmail-do-bcc delimline))))
+
+(defun smtpmail-queue-mail (tembuf smtpmail-code-conv-from)
+  (let* ((file-data
+	  (expand-file-name
+	   (format "%s_%i"
+		   (format-time-string "%Y-%m-%d_%H:%M:%S")
+		   (setq smtpmail-queue-counter
+			 (1+ smtpmail-queue-counter)))
+	   smtpmail-queue-dir))
+	 (file-data (convert-standard-filename file-data))
+	 (file-elisp (concat file-data ".el"))
+	 (buffer-data (create-file-buffer file-data)))
+    (unless (file-exists-p smtpmail-queue-dir)
+      (make-directory smtpmail-queue-dir t))
+    (with-current-buffer buffer-data
+      (erase-buffer)
+      (set-buffer-file-coding-system
+       ;; We will be reading the file with no-conversion in
+       ;; smtpmail-send-queued-mail below, so write it out
+       ;; with Unix EOLs.
+       (coding-system-change-eol-conversion
+	(or smtpmail-code-conv-from 'undecided)
+	'unix)
+       nil t)
+      (insert-buffer-substring tembuf)
+      (write-file file-data)
+      (let ((coding-system-for-write 'utf-8))
+        (with-temp-buffer
+          (insert "(setq ")
+          (dolist (var (cons 'smtpmail-recipient-address-list
+                             ;; Perhaps store the server etc.
+                             (and smtpmail-store-queue-variables
+                                  smtpmail--stored-queue-variables)))
+            (insert (format "     %s %S\n" var (symbol-value var))))
+          (insert ")\n")
+          (write-region (point-min) (point-max) file-elisp
+                        nil 'silent)))
+      (write-region (concat file-data "\n") nil
+                    (expand-file-name smtpmail-queue-index-file
+                                      smtpmail-queue-dir)
+                    t 'silent))
+    (kill-buffer buffer-data)))
+
+(defun smtpmail-send-mail (tembuf)
+  (if (not (null smtpmail-recipient-address-list))
+      (when (setq result
+                  (smtpmail-via-smtp
+                   smtpmail-recipient-address-list tembuf))
+        (error "Sending failed: %s"
+               (smtpmail--sanitize-error-message result)))
+    (error "Sending failed; no recipients")))
 
 ;;;###autoload
 (defun smtpmail-send-it ()
   (let ((errbuf (if mail-interactive
 		    (generate-new-buffer " smtpmail errors")
 		  0))
-	(tembuf (generate-new-buffer " smtpmail temp"))
-	(case-fold-search nil)
-	delimline
-	result
-	(mailbuf (current-buffer))
-        ;; Examine this variable now, so that
-	;; local binding in the mail buffer will take effect.
-	(smtpmail-mail-address
-         (save-restriction
-           ;; Only look at the headers when fetching the
-           ;; envelope address.
-           (message-narrow-to-headers)
-           (or (and mail-specify-envelope-from (mail-envelope-from))
-               (let ((from (mail-fetch-field "from")))
-	         (and from
-		      (cadr (mail-extract-address-components from))))
-	       (smtpmail-user-mail-address))))
-	(smtpmail-code-conv-from
-	 (if enable-multibyte-characters
-	     (let ((sendmail-coding-system smtpmail-code-conv-from))
-	       (select-message-coding-system)))))
+        (tembuf (generate-new-buffer " smtpmail temp")))
     (unwind-protect
-	(with-current-buffer tembuf
-	  (erase-buffer)
-	  ;; Use the same `buffer-file-coding-system' as in the mail
-	  ;; buffer, otherwise any `write-region' invocations (e.g., in
-	  ;; mail-do-fcc below) will annoy with asking for a suitable
-	  ;; encoding.
-	  (set-buffer-file-coding-system smtpmail-code-conv-from nil t)
-	  (insert-buffer-substring mailbuf)
-	  (goto-char (point-max))
-	  ;; require one newline at the end.
-	  (or (= (preceding-char) ?\n)
-	      (insert ?\n))
-	  ;; Change header-delimiter to be what sendmail expects.
-	  (mail-sendmail-undelimit-header)
-	  (setq delimline (point-marker))
-          ;; (sendmail-synch-aliases)
-	  (if mail-aliases
-	      (expand-mail-aliases (point-min) delimline))
-	  (goto-char (point-min))
-	  ;; ignore any blank lines in the header
-	  (while (and (re-search-forward "\n\n\n*" delimline t)
-		      (< (point) delimline))
-	    (replace-match "\n"))
-	  (let ((case-fold-search t))
-	    ;; We used to process Resent-... headers here,
-	    ;; but it was not done properly, and the job
-	    ;; is done correctly in `smtpmail-deduce-address-list'.
-	    ;; Don't send out a blank subject line
-	    (goto-char (point-min))
-	    (if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t)
-		(replace-match "")
-	      ;; This one matches a Subject just before the header delimiter.
-	      (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t)
-		       (= (match-end 0) delimline))
-		  (replace-match "")))
-	    ;; Put the "From:" field in unless for some odd reason
-	    ;; they put one in themselves.
-	    (goto-char (point-min))
-	    (if (not (re-search-forward "^From:" delimline t))
-		(let* ((login smtpmail-mail-address)
-		       (fullname (user-full-name)))
-		  (cond ((eq mail-from-style 'angles)
-			 (insert "From: " fullname)
-			 (let ((fullname-start (+ (point-min) 6))
-			       (fullname-end (point-marker)))
-			   (goto-char fullname-start)
-			   ;; Look for a character that cannot appear unquoted
-			   ;; according to RFC 822 or its successors.
-			   (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]"
-						  fullname-end 1)
-			       (progn
-				 ;; Quote fullname, escaping specials.
-				 (goto-char fullname-start)
-				 (insert "\"")
-				 (while (re-search-forward "[\"\\]"
-							   fullname-end 1)
-				   (replace-match "\\\\\\&" t))
-				 (insert "\""))))
-			 (insert " <" login ">\n"))
-			((eq mail-from-style 'parens)
-			 (insert "From: " login " (")
-			 (let ((fullname-start (point)))
-			   (insert fullname)
-			   (let ((fullname-end (point-marker)))
-			     (goto-char fullname-start)
-			     ;; RFC 822 and its successors say \ and
-			     ;; nonmatching parentheses must be
-			     ;; escaped in comments.
-			     ;; Escape every instance of ()\ ...
-			     (while (re-search-forward "[()\\]" fullname-end 1)
-			       (replace-match "\\\\\\&" t))
-			     ;; ... then undo escaping of matching parentheses,
-			     ;; including matching nested parentheses.
-			     (goto-char fullname-start)
-			     (while (re-search-forward
-				     "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
-				     fullname-end 1)
-			       (replace-match "\\1(\\3)" t)
-			       (goto-char fullname-start))))
-			 (insert ")\n"))
-			((null mail-from-style)
-			 (insert "From: " login "\n")))))
-	    ;; Insert a `Message-Id:' field if there isn't one yet.
-	    (goto-char (point-min))
-	    (unless (re-search-forward "^Message-Id:" delimline t)
-	      (insert "Message-Id: " (message-make-message-id) "\n"))
-	    ;; Insert a `Date:' field if there isn't one yet.
-	    (goto-char (point-min))
-	    (unless (re-search-forward "^Date:" delimline t)
-	      (insert "Date: " (message-make-date) "\n"))
-	    ;; Possibly add a MIME header for the current coding system
-	    (let (charset)
-	      (goto-char (point-min))
-	      (and (eq mail-send-nonascii 'mime)
-		   (not (re-search-forward "^MIME-version:" delimline t))
-		   (progn (skip-chars-forward "\0-\177")
-			  (/= (point) (point-max)))
-		   smtpmail-code-conv-from
-		   (setq charset
-			 (coding-system-get smtpmail-code-conv-from
-					    'mime-charset))
-		   (goto-char delimline)
-		   (insert "MIME-version: 1.0\n"
-			   "Content-type: text/plain; charset="
-			   (symbol-name charset)
-			   "\nContent-Transfer-Encoding: 8bit\n")))
-	    ;; Insert an extra newline if we need it to work around
-	    ;; Sun's bug that swallows newlines.
-	    (goto-char (1+ delimline))
-	    ;; Find and handle any Fcc fields.
-	    (goto-char (point-min))
-	    (if (re-search-forward "^Fcc:" delimline t)
-		;; Force `mail-do-fcc' to use the encoding of the mail
-		;; buffer to encode outgoing messages on Fcc files.
-		(let ((coding-system-for-write
-		       ;; mbox files must have Unix EOLs.
-		       (coding-system-change-eol-conversion
-			smtpmail-code-conv-from 'unix)))
-		  (mail-do-fcc delimline)))
-	    (if mail-interactive
-		(with-current-buffer errbuf
-		  (erase-buffer))))
-	  ;; Encode the header according to RFC2047.
-	  (mail-encode-header (point-min) delimline)
-	  ;;
-	  (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*"))
-	  (setq smtpmail-recipient-address-list
-                (smtpmail-deduce-address-list tembuf (point-min) delimline))
-	  (kill-buffer smtpmail-address-buffer)
-
-	  (smtpmail-do-bcc delimline)
-          ;; Send or queue
-	  (if (not smtpmail-queue-mail)
-	      (if (not (null smtpmail-recipient-address-list))
-		  (when (setq result
-			      (smtpmail-via-smtp
-			       smtpmail-recipient-address-list tembuf))
-		    (error "Sending failed: %s"
-                           (smtpmail--sanitize-error-message result)))
-		(error "Sending failed; no recipients"))
-	    (let* ((file-data
-		    (expand-file-name
-		     (format "%s_%i"
-			     (format-time-string "%Y-%m-%d_%H:%M:%S")
-			     (setq smtpmail-queue-counter
-				   (1+ smtpmail-queue-counter)))
-		     smtpmail-queue-dir))
-		   (file-data (convert-standard-filename file-data))
-		   (file-elisp (concat file-data ".el"))
-		   (buffer-data (create-file-buffer file-data)))
-	      (unless (file-exists-p smtpmail-queue-dir)
-		(make-directory smtpmail-queue-dir t))
-	      (with-current-buffer buffer-data
-		(erase-buffer)
-		(set-buffer-file-coding-system
-		 ;; We will be reading the file with no-conversion in
-		 ;; smtpmail-send-queued-mail below, so write it out
-		 ;; with Unix EOLs.
-		 (coding-system-change-eol-conversion
-		  (or smtpmail-code-conv-from 'undecided)
-		  'unix)
-		 nil t)
-		(insert-buffer-substring tembuf)
-		(write-file file-data)
-                (let ((coding-system-for-write 'utf-8))
-                  (with-temp-buffer
-                    (insert "(setq ")
-                    (dolist (var (cons 'smtpmail-recipient-address-list
-                                       ;; Perhaps store the server etc.
-                                       (and smtpmail-store-queue-variables
-                                            smtpmail--stored-queue-variables)))
-                      (insert (format "     %s %S\n" var (symbol-value var))))
-                    (insert ")\n")
-                    (write-region (point-min) (point-max) file-elisp
-                                  nil 'silent)))
-		(write-region (concat file-data "\n") nil
-                              (expand-file-name smtpmail-queue-index-file
-                                                smtpmail-queue-dir)
-                              t 'silent))
-	      (kill-buffer buffer-data))))
+        (let ((smtpmail-code-conv-from
+	       (if enable-multibyte-characters
+	           (let ((sendmail-coding-system smtpmail-code-conv-from))
+	             (select-message-coding-system)))))
+          (smtpmail-prepare-mail tembuf errbuf smtpmail-code-conv-from)
+          (if smtpmail-queue-mail
+              (smtpmail-queue-mail tembuf smtpmail-code-conv-from)
+            (smtpmail-send-mail tembuf)))
       (kill-buffer tembuf)
       (if (bufferp errbuf)
 	  (kill-buffer errbuf)))))
-- 
2.40.0


[-- Attachment #3: Type: text/plain, Size: 7350 bytes --]



In GNU Emacs 30.0.50 (build 1, x86_64-unknown-openbsd7.3, cairo version
 1.17.8) of 2023-05-05 built on computer
Repository revision: f204c4a6cfa77fdbb2573b728110576e206b0b20
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12101006
System Description: OpenBSD computer 7.3 GENERIC.MP#1125 amd64

Configured using:
 'configure --prefix=/home/manuel/emacs --bindir=/home/manuel/bin
 --with-x-toolkit=no --without-sound --without-compress-install
 CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib'

Configured features:
CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG JSON
LCMS2 LIBOTF LIBXML2 MODULES NOTIFY KQUEUE OLDXMENU PDUMPER PNG RSVG
SQLITE3 THREADS TIFF TREE_SITTER WEBP X11 XDBE XIM XINPUT2 XPM ZLIB

Important settings:
  value of $LC_ALL: en_US.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Magit

Minor modes in effect:
  global-git-commit-mode: t
  magit-auto-revert-mode: t
  display-time-mode: t
  display-battery-mode: t
  server-mode: t
  shell-dirtrack-mode: t
  override-global-mode: t
  repeat-mode: t
  desktop-save-mode: t
  global-eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  buffer-read-only: t
  line-number-mode: t
  indent-tabs-mode: t
  transient-mark-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t

Load-path shadows:
/home/manuel/.emacs.d/elpa/ef-themes-0.11.0/theme-loaddefs hides /home/manuel/emacs/share/emacs/30.0.50/lisp/theme-loaddefs
/home/manuel/.emacs.d/elpa/transient-0.3.7/transient hides /home/manuel/emacs/share/emacs/30.0.50/lisp/transient

Features:
(shadow goto-addr dabbrev emacsbug whitespace magit-patch misearch
multi-isearch magit-extras face-remap magit-submodule magit-obsolete
magit-blame magit-stash magit-reflog magit-bisect magit-push magit-pull
magit-fetch magit-clone magit-remote magit-commit magit-sequence
magit-notes magit-worktree magit-tag magit-merge magit-branch
magit-reset magit-files magit-refs magit-status magit magit-repos
magit-apply magit-wip magit-log which-func imenu magit-diff smerge-mode
diff git-commit log-edit add-log magit-core magit-autorevert
magit-margin magit-transient magit-process with-editor magit-mode
transient magit-git magit-section magit-utils dash shr-color gnus-cite
gnus-async gnus-bcklg gnus-ml gnus-topic mm-archive url-cache qp utf-7
imap rfc2104 nndoc nndraft nnmh nnfolder nnml gnus-agent gnus-srvr
gnus-score score-mode nnvirtual nntp gnus-cache nnrss mm-url
network-stream mailalias textsec uni-scripts idna-mapping ucs-normalize
uni-confusable textsec-check sort mail-extr pulse tabify cus-edit
cus-start cl-print smtpmail help-fns radix-tree vc-bzr vc-src vc-sccs
vc-cvs vc-rcs log-view pcvs-util sh-script smie treesit executable vc-hg
conf-mode view pascal vc mule-util hi-lock autorevert filenotify vc-git
diff-mode vc-dispatcher vc-svn bug-reference paredit gnus-dired time
battery cus-load exwm-randr xcb-randr exwm-config ido exwm exwm-input
xcb-keysyms xcb-xkb exwm-manage exwm-floating xcb-cursor xcb-render
exwm-layout exwm-workspace exwm-core xcb-ewmh xcb-icccm xcb xcb-xproto
xcb-types xcb-debug server modus-operandi-theme modus-themes zone
speed-type url-http url-auth url-gw nsm compat ytdious mingus libmpdee
reporter edebug debug backtrace transmission color calc-bin calc-ext
calc calc-loaddefs rect calc-macs supercite regi ebdb-message ebdb-gnus
gnus-msg gnus-art mm-uu mml2015 mm-view mml-smime smime gnutls dig
gnus-sum shr pixel-fill kinsoku url-file svg dom gnus-group gnus-undo
gnus-start gnus-dbus gnus-cloud nnimap nnmail mail-source utf7 nnoo
gnus-spec gnus-int gnus-range message sendmail yank-media puny rfc822
mml mml-sec epa epg rfc6068 epg-config mm-decode mm-bodies mm-encode
mail-parse rfc2231 rfc2047 rfc2045 ietf-drums gmm-utils mailheader
gnus-win gnus nnheader gnus-util mail-utils range mm-util mail-prsvr
wid-edit ebdb-mua ebdb-com crm ebdb-format ebdb mailabbrev eieio-opt
speedbar ezimage dframe find-func eieio-base pcase timezone
visual-basic-mode cl web-mode derived disp-table erlang-start
smart-tabs-mode skeleton cc-mode cc-fonts cc-guess cc-menus cc-cmds
cc-styles cc-align cc-engine cc-vars cc-defs slime-asdf grep slime-tramp
tramp rx tramp-loaddefs trampver tramp-integration files-x tramp-compat
xdg shell pcomplete parse-time iso8601 time-date ls-lisp format-spec
slime-fancy slime-indentation slime-cl-indent cl-indent
slime-trace-dialog slime-fontifying-fu slime-package-fu slime-references
slime-compiler-notes-tree advice slime-scratch slime-presentations
bridge slime-macrostep macrostep slime-mdot-fu slime-enclosing-context
slime-fuzzy slime-fancy-trace slime-fancy-inspector slime-c-p-c
slime-editing-commands slime-autodoc slime-repl slime-parse slime
apropos compile text-property-search etags fileloop generator xref
project arc-mode archive-mode noutline outline icons pp comint ansi-osc
ansi-color ring hyperspec thingatpt slime-autoloads edmacro kmacro
use-package-bind-key bind-key appt diary-lib diary-loaddefs cal-menu
calendar cal-loaddefs dired-x dired-aux dired dired-loaddefs
notifications dbus xml cl-extra help-mode use-package-core repeat
easy-mmode desktop frameset rust-mode-autoloads speed-type-autoloads
osm-autoloads ebdb-autoloads compat-autoloads magit-autoloads
debbugs-autoloads git-commit-autoloads magit-section-autoloads
ef-themes-autoloads with-editor-autoloads paredit-autoloads
dash-autoloads ytdious-autoloads transmission-autoloads
transient-autoloads exwm-autoloads hyperbole-autoloads
detached-autoloads info package browse-url url url-proxy url-privacy
url-expand url-methods url-history url-cookie generate-lisp-file
url-domsuf url-util mailcap url-handlers url-parse auth-source cl-seq
eieio eieio-core cl-macs password-cache json subr-x map byte-opt gv
bytecomp byte-compile url-vars cl-loaddefs cl-lib rmc iso-transl tooltip
cconv eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type
elisp-mode mwheel term/x-win x-win term/common-win x-dnd tool-bar dnd
fontset image regexp-opt fringe tabulated-list replace newcomment
text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow
isearch easymenu timer select scroll-bar mouse jit-lock font-lock syntax
font-core term/tty-colors frame minibuffer nadvice seq simple cl-generic
indonesian philippine cham georgian utf-8-lang misc-lang vietnamese
tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek
romanian slovak czech european ethiopic indian cyrillic chinese
composite emoji-zwj charscript charprop case-table epa-hook
jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs
theme-loaddefs faces cus-face macroexp files window text-properties
overlay sha1 md5 base64 format env code-pages mule custom widget keymap
hashtable-print-readable backquote threads dbusbind kqueue lcms2
dynamic-setting system-font-setting font-render-setting cairo xinput2 x
multi-tty make-network-process emacs)

Memory information:
((conses 16 933133 308956)
 (symbols 48 55180 35)
 (strings 32 272198 12320)
 (string-bytes 1 8555283)
 (vectors 16 173055)
 (vector-slots 8 2925695 155806)
 (floats 8 544 5262)
 (intervals 56 18111 2469)
 (buffers 984 113))

-- 
Manuel Giraud

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-05-05 13:13 bug#63311: 30.0.50; [PATCH] smtpmail-send-it split Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-05-05 18:57 ` Eli Zaretskii
       [not found]   ` <874joq34bk.fsf@ledu-giraud.fr>
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-05-05 18:57 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> Date: Fri, 05 May 2023 15:13:32 +0200
> From:  Manuel Giraud via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> 
> BTW, does anyone know the purpose of 'errbuf': I see it is created then
> erased and then killed?

Looks like a left-over from when this function was written.  It is
basically a rewrite of sendmail-send-it, which does use that variable.





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
       [not found]   ` <874joq34bk.fsf@ledu-giraud.fr>
@ 2023-05-06  6:20     ` Eli Zaretskii
  2023-05-06  9:34       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-09  9:52       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 41+ messages in thread
From: Eli Zaretskii @ 2023-05-06  6:20 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Date: Fri, 05 May 2023 22:34:39 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> Date: Fri, 05 May 2023 15:13:32 +0200
> >> From:  Manuel Giraud via "Bug reports for GNU Emacs,
> >>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> >> 
> >> BTW, does anyone know the purpose of 'errbuf': I see it is created then
> >> erased and then killed?
> >
> > Looks like a left-over from when this function was written.  It is
> > basically a rewrite of sendmail-send-it, which does use that variable.
> 
> Ok.  Do you want me to upgrade this patch removing errbuf?

Sure, that's a good cleanup.

(And please use Reply All, to have this discussion recorded by the
tracker.)





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-05-06  6:20     ` Eli Zaretskii
@ 2023-05-06  9:34       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-09  9:52       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-06  9:34 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

[-- Attachment #1: Type: text/plain, Size: 282 bytes --]

Eli Zaretskii <eliz@gnu.org> writes:

[...]

>> Ok.  Do you want me to upgrade this patch removing errbuf?
>
> Sure, that's a good cleanup.

Ok.  Here is the modified patch.

> (And please use Reply All, to have this discussion recorded by the
> tracker.)

Sure.  Sorry about that.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-smtpmail-send-it-split.patch --]
[-- Type: text/x-patch, Size: 18269 bytes --]

From dfcaa8d0b9ec3fa0087326bb06dcdda5895f7142 Mon Sep 17 00:00:00 2001
From: Manuel Giraud <manuel@ledu-giraud.fr>
Date: Fri, 5 May 2023 14:35:01 +0200
Subject: [PATCH] smtpmail-send-it split

* lisp/mail/smtpmail.el (smtpmail-prepare-mail): New function that
prepares the mail with current buffer content.
(smtpmail-queue-mail): New function to queue a mail (prepared by
'smtpmail-prepare-mail').
(smtpmail-send-mail): New function to send a mail (prepared by
'smtpmail-send-mail').
(smtpmail-send-it): Use all three previous functions.  While here,
remove 'errbuf' leftovers.
---
 lisp/mail/smtpmail.el | 411 +++++++++++++++++++++---------------------
 1 file changed, 204 insertions(+), 207 deletions(-)

diff --git a/lisp/mail/smtpmail.el b/lisp/mail/smtpmail.el
index 78688d170cc..2c23e97afd0 100644
--- a/lisp/mail/smtpmail.el
+++ b/lisp/mail/smtpmail.el
@@ -205,217 +205,214 @@ smtpmail-mail-address
   "Value to use for envelope-from address for mail from ambient buffer.")
 
 ;;; Functions
+(defun smtpmail-prepare-mail (tembuf smtpmail-code-conv-from)
+    (let ((case-fold-search nil)
+	  delimline
+	  (mailbuf (current-buffer))
+         ;; Examine this variable now, so that
+	 ;; local binding in the mail buffer will take effect.
+	 (smtpmail-mail-address
+          (save-restriction
+            ;; Only look at the headers when fetching the
+            ;; envelope address.
+            (message-narrow-to-headers)
+            (or (and mail-specify-envelope-from (mail-envelope-from))
+                (let ((from (mail-fetch-field "from")))
+	          (and from
+		       (cadr (mail-extract-address-components from))))
+	        (smtpmail-user-mail-address)))))
+    (with-current-buffer tembuf
+      (erase-buffer)
+      ;; Use the same `buffer-file-coding-system' as in the mail
+      ;; buffer, otherwise any `write-region' invocations (e.g., in
+      ;; mail-do-fcc below) will annoy with asking for a suitable
+      ;; encoding.
+      (set-buffer-file-coding-system smtpmail-code-conv-from nil t)
+      (insert-buffer-substring mailbuf)
+      (goto-char (point-max))
+      ;; require one newline at the end.
+      (or (= (preceding-char) ?\n)
+	  (insert ?\n))
+      ;; Change header-delimiter to be what sendmail expects.
+      (mail-sendmail-undelimit-header)
+      (setq delimline (point-marker))
+      (if mail-aliases
+	  (expand-mail-aliases (point-min) delimline))
+      (goto-char (point-min))
+      ;; ignore any blank lines in the header
+      (while (and (re-search-forward "\n\n\n*" delimline t)
+		  (< (point) delimline))
+	(replace-match "\n"))
+      (let ((case-fold-search t))
+	;; We used to process Resent-... headers here,
+	;; but it was not done properly, and the job
+	;; is done correctly in `smtpmail-deduce-address-list'.
+	;; Don't send out a blank subject line
+	(goto-char (point-min))
+	(if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t)
+	    (replace-match "")
+	  ;; This one matches a Subject just before the header delimiter.
+	  (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t)
+		   (= (match-end 0) delimline))
+	      (replace-match "")))
+	;; Put the "From:" field in unless for some odd reason
+	;; they put one in themselves.
+	(goto-char (point-min))
+	(if (not (re-search-forward "^From:" delimline t))
+	    (let* ((login smtpmail-mail-address)
+		   (fullname (user-full-name)))
+	      (cond ((eq mail-from-style 'angles)
+		     (insert "From: " fullname)
+		     (let ((fullname-start (+ (point-min) 6))
+			   (fullname-end (point-marker)))
+		       (goto-char fullname-start)
+		       ;; Look for a character that cannot appear unquoted
+		       ;; according to RFC 822 or its successors.
+		       (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]"
+					      fullname-end 1)
+			   (progn
+			     ;; Quote fullname, escaping specials.
+			     (goto-char fullname-start)
+			     (insert "\"")
+			     (while (re-search-forward "[\"\\]"
+						       fullname-end 1)
+			       (replace-match "\\\\\\&" t))
+			     (insert "\""))))
+		     (insert " <" login ">\n"))
+		    ((eq mail-from-style 'parens)
+		     (insert "From: " login " (")
+		     (let ((fullname-start (point)))
+		       (insert fullname)
+		       (let ((fullname-end (point-marker)))
+			 (goto-char fullname-start)
+			 ;; RFC 822 and its successors say \ and
+			 ;; nonmatching parentheses must be
+			 ;; escaped in comments.
+			 ;; Escape every instance of ()\ ...
+			 (while (re-search-forward "[()\\]" fullname-end 1)
+			   (replace-match "\\\\\\&" t))
+			 ;; ... then undo escaping of matching parentheses,
+			 ;; including matching nested parentheses.
+			 (goto-char fullname-start)
+			 (while (re-search-forward
+				 "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
+				 fullname-end 1)
+			   (replace-match "\\1(\\3)" t)
+			   (goto-char fullname-start))))
+		     (insert ")\n"))
+		    ((null mail-from-style)
+		     (insert "From: " login "\n")))))
+	;; Insert a `Message-Id:' field if there isn't one yet.
+	(goto-char (point-min))
+	(unless (re-search-forward "^Message-Id:" delimline t)
+	  (insert "Message-Id: " (message-make-message-id) "\n"))
+	;; Insert a `Date:' field if there isn't one yet.
+	(goto-char (point-min))
+	(unless (re-search-forward "^Date:" delimline t)
+	  (insert "Date: " (message-make-date) "\n"))
+	;; Possibly add a MIME header for the current coding system
+	(let (charset)
+	  (goto-char (point-min))
+	  (and (eq mail-send-nonascii 'mime)
+	       (not (re-search-forward "^MIME-version:" delimline t))
+	       (progn (skip-chars-forward "\0-\177")
+		      (/= (point) (point-max)))
+	       smtpmail-code-conv-from
+	       (setq charset
+		     (coding-system-get smtpmail-code-conv-from
+					'mime-charset))
+	       (goto-char delimline)
+	       (insert "MIME-version: 1.0\n"
+		       "Content-type: text/plain; charset="
+		       (symbol-name charset)
+		       "\nContent-Transfer-Encoding: 8bit\n")))
+	;; Insert an extra newline if we need it to work around
+	;; Sun's bug that swallows newlines.
+	(goto-char (1+ delimline))
+	;; Find and handle any Fcc fields.
+	(goto-char (point-min))
+	(if (re-search-forward "^Fcc:" delimline t)
+	    ;; Force `mail-do-fcc' to use the encoding of the mail
+	    ;; buffer to encode outgoing messages on Fcc files.
+	    (let ((coding-system-for-write
+		   ;; mbox files must have Unix EOLs.
+		   (coding-system-change-eol-conversion
+		    smtpmail-code-conv-from 'unix)))
+	      (mail-do-fcc delimline))))
+      ;; Encode the header according to RFC2047.
+      (mail-encode-header (point-min) delimline)
+      ;;
+      (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*"))
+      (setq smtpmail-recipient-address-list
+            (smtpmail-deduce-address-list tembuf (point-min) delimline))
+      (kill-buffer smtpmail-address-buffer)
+
+      (smtpmail-do-bcc delimline))))
+
+(defun smtpmail-queue-mail (tembuf smtpmail-code-conv-from)
+  (let* ((file-data
+	  (expand-file-name
+	   (format "%s_%i"
+		   (format-time-string "%Y-%m-%d_%H:%M:%S")
+		   (setq smtpmail-queue-counter
+			 (1+ smtpmail-queue-counter)))
+	   smtpmail-queue-dir))
+	 (file-data (convert-standard-filename file-data))
+	 (file-elisp (concat file-data ".el"))
+	 (buffer-data (create-file-buffer file-data)))
+    (unless (file-exists-p smtpmail-queue-dir)
+      (make-directory smtpmail-queue-dir t))
+    (with-current-buffer buffer-data
+      (erase-buffer)
+      (set-buffer-file-coding-system
+       ;; We will be reading the file with no-conversion in
+       ;; smtpmail-send-queued-mail below, so write it out
+       ;; with Unix EOLs.
+       (coding-system-change-eol-conversion
+	(or smtpmail-code-conv-from 'undecided)
+	'unix)
+       nil t)
+      (insert-buffer-substring tembuf)
+      (write-file file-data)
+      (let ((coding-system-for-write 'utf-8))
+        (with-temp-buffer
+          (insert "(setq ")
+          (dolist (var (cons 'smtpmail-recipient-address-list
+                             ;; Perhaps store the server etc.
+                             (and smtpmail-store-queue-variables
+                                  smtpmail--stored-queue-variables)))
+            (insert (format "     %s %S\n" var (symbol-value var))))
+          (insert ")\n")
+          (write-region (point-min) (point-max) file-elisp
+                        nil 'silent)))
+      (write-region (concat file-data "\n") nil
+                    (expand-file-name smtpmail-queue-index-file
+                                      smtpmail-queue-dir)
+                    t 'silent))
+    (kill-buffer buffer-data)))
+
+(defun smtpmail-send-mail (tembuf)
+  (if (not (null smtpmail-recipient-address-list))
+      (when (setq result
+                  (smtpmail-via-smtp
+                   smtpmail-recipient-address-list tembuf))
+        (error "Sending failed: %s"
+               (smtpmail--sanitize-error-message result)))
+    (error "Sending failed; no recipients")))
 
 ;;;###autoload
 (defun smtpmail-send-it ()
-  (let ((errbuf (if mail-interactive
-		    (generate-new-buffer " smtpmail errors")
-		  0))
-	(tembuf (generate-new-buffer " smtpmail temp"))
-	(case-fold-search nil)
-	delimline
-	result
-	(mailbuf (current-buffer))
-        ;; Examine this variable now, so that
-	;; local binding in the mail buffer will take effect.
-	(smtpmail-mail-address
-         (save-restriction
-           ;; Only look at the headers when fetching the
-           ;; envelope address.
-           (message-narrow-to-headers)
-           (or (and mail-specify-envelope-from (mail-envelope-from))
-               (let ((from (mail-fetch-field "from")))
-	         (and from
-		      (cadr (mail-extract-address-components from))))
-	       (smtpmail-user-mail-address))))
-	(smtpmail-code-conv-from
-	 (if enable-multibyte-characters
-	     (let ((sendmail-coding-system smtpmail-code-conv-from))
-	       (select-message-coding-system)))))
+  (let ((tembuf (generate-new-buffer " smtpmail temp")))
     (unwind-protect
-	(with-current-buffer tembuf
-	  (erase-buffer)
-	  ;; Use the same `buffer-file-coding-system' as in the mail
-	  ;; buffer, otherwise any `write-region' invocations (e.g., in
-	  ;; mail-do-fcc below) will annoy with asking for a suitable
-	  ;; encoding.
-	  (set-buffer-file-coding-system smtpmail-code-conv-from nil t)
-	  (insert-buffer-substring mailbuf)
-	  (goto-char (point-max))
-	  ;; require one newline at the end.
-	  (or (= (preceding-char) ?\n)
-	      (insert ?\n))
-	  ;; Change header-delimiter to be what sendmail expects.
-	  (mail-sendmail-undelimit-header)
-	  (setq delimline (point-marker))
-          ;; (sendmail-synch-aliases)
-	  (if mail-aliases
-	      (expand-mail-aliases (point-min) delimline))
-	  (goto-char (point-min))
-	  ;; ignore any blank lines in the header
-	  (while (and (re-search-forward "\n\n\n*" delimline t)
-		      (< (point) delimline))
-	    (replace-match "\n"))
-	  (let ((case-fold-search t))
-	    ;; We used to process Resent-... headers here,
-	    ;; but it was not done properly, and the job
-	    ;; is done correctly in `smtpmail-deduce-address-list'.
-	    ;; Don't send out a blank subject line
-	    (goto-char (point-min))
-	    (if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t)
-		(replace-match "")
-	      ;; This one matches a Subject just before the header delimiter.
-	      (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t)
-		       (= (match-end 0) delimline))
-		  (replace-match "")))
-	    ;; Put the "From:" field in unless for some odd reason
-	    ;; they put one in themselves.
-	    (goto-char (point-min))
-	    (if (not (re-search-forward "^From:" delimline t))
-		(let* ((login smtpmail-mail-address)
-		       (fullname (user-full-name)))
-		  (cond ((eq mail-from-style 'angles)
-			 (insert "From: " fullname)
-			 (let ((fullname-start (+ (point-min) 6))
-			       (fullname-end (point-marker)))
-			   (goto-char fullname-start)
-			   ;; Look for a character that cannot appear unquoted
-			   ;; according to RFC 822 or its successors.
-			   (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]"
-						  fullname-end 1)
-			       (progn
-				 ;; Quote fullname, escaping specials.
-				 (goto-char fullname-start)
-				 (insert "\"")
-				 (while (re-search-forward "[\"\\]"
-							   fullname-end 1)
-				   (replace-match "\\\\\\&" t))
-				 (insert "\""))))
-			 (insert " <" login ">\n"))
-			((eq mail-from-style 'parens)
-			 (insert "From: " login " (")
-			 (let ((fullname-start (point)))
-			   (insert fullname)
-			   (let ((fullname-end (point-marker)))
-			     (goto-char fullname-start)
-			     ;; RFC 822 and its successors say \ and
-			     ;; nonmatching parentheses must be
-			     ;; escaped in comments.
-			     ;; Escape every instance of ()\ ...
-			     (while (re-search-forward "[()\\]" fullname-end 1)
-			       (replace-match "\\\\\\&" t))
-			     ;; ... then undo escaping of matching parentheses,
-			     ;; including matching nested parentheses.
-			     (goto-char fullname-start)
-			     (while (re-search-forward
-				     "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
-				     fullname-end 1)
-			       (replace-match "\\1(\\3)" t)
-			       (goto-char fullname-start))))
-			 (insert ")\n"))
-			((null mail-from-style)
-			 (insert "From: " login "\n")))))
-	    ;; Insert a `Message-Id:' field if there isn't one yet.
-	    (goto-char (point-min))
-	    (unless (re-search-forward "^Message-Id:" delimline t)
-	      (insert "Message-Id: " (message-make-message-id) "\n"))
-	    ;; Insert a `Date:' field if there isn't one yet.
-	    (goto-char (point-min))
-	    (unless (re-search-forward "^Date:" delimline t)
-	      (insert "Date: " (message-make-date) "\n"))
-	    ;; Possibly add a MIME header for the current coding system
-	    (let (charset)
-	      (goto-char (point-min))
-	      (and (eq mail-send-nonascii 'mime)
-		   (not (re-search-forward "^MIME-version:" delimline t))
-		   (progn (skip-chars-forward "\0-\177")
-			  (/= (point) (point-max)))
-		   smtpmail-code-conv-from
-		   (setq charset
-			 (coding-system-get smtpmail-code-conv-from
-					    'mime-charset))
-		   (goto-char delimline)
-		   (insert "MIME-version: 1.0\n"
-			   "Content-type: text/plain; charset="
-			   (symbol-name charset)
-			   "\nContent-Transfer-Encoding: 8bit\n")))
-	    ;; Insert an extra newline if we need it to work around
-	    ;; Sun's bug that swallows newlines.
-	    (goto-char (1+ delimline))
-	    ;; Find and handle any Fcc fields.
-	    (goto-char (point-min))
-	    (if (re-search-forward "^Fcc:" delimline t)
-		;; Force `mail-do-fcc' to use the encoding of the mail
-		;; buffer to encode outgoing messages on Fcc files.
-		(let ((coding-system-for-write
-		       ;; mbox files must have Unix EOLs.
-		       (coding-system-change-eol-conversion
-			smtpmail-code-conv-from 'unix)))
-		  (mail-do-fcc delimline)))
-	    (if mail-interactive
-		(with-current-buffer errbuf
-		  (erase-buffer))))
-	  ;; Encode the header according to RFC2047.
-	  (mail-encode-header (point-min) delimline)
-	  ;;
-	  (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*"))
-	  (setq smtpmail-recipient-address-list
-                (smtpmail-deduce-address-list tembuf (point-min) delimline))
-	  (kill-buffer smtpmail-address-buffer)
-
-	  (smtpmail-do-bcc delimline)
-          ;; Send or queue
-	  (if (not smtpmail-queue-mail)
-	      (if (not (null smtpmail-recipient-address-list))
-		  (when (setq result
-			      (smtpmail-via-smtp
-			       smtpmail-recipient-address-list tembuf))
-		    (error "Sending failed: %s"
-                           (smtpmail--sanitize-error-message result)))
-		(error "Sending failed; no recipients"))
-	    (let* ((file-data
-		    (expand-file-name
-		     (format "%s_%i"
-			     (format-time-string "%Y-%m-%d_%H:%M:%S")
-			     (setq smtpmail-queue-counter
-				   (1+ smtpmail-queue-counter)))
-		     smtpmail-queue-dir))
-		   (file-data (convert-standard-filename file-data))
-		   (file-elisp (concat file-data ".el"))
-		   (buffer-data (create-file-buffer file-data)))
-	      (unless (file-exists-p smtpmail-queue-dir)
-		(make-directory smtpmail-queue-dir t))
-	      (with-current-buffer buffer-data
-		(erase-buffer)
-		(set-buffer-file-coding-system
-		 ;; We will be reading the file with no-conversion in
-		 ;; smtpmail-send-queued-mail below, so write it out
-		 ;; with Unix EOLs.
-		 (coding-system-change-eol-conversion
-		  (or smtpmail-code-conv-from 'undecided)
-		  'unix)
-		 nil t)
-		(insert-buffer-substring tembuf)
-		(write-file file-data)
-                (let ((coding-system-for-write 'utf-8))
-                  (with-temp-buffer
-                    (insert "(setq ")
-                    (dolist (var (cons 'smtpmail-recipient-address-list
-                                       ;; Perhaps store the server etc.
-                                       (and smtpmail-store-queue-variables
-                                            smtpmail--stored-queue-variables)))
-                      (insert (format "     %s %S\n" var (symbol-value var))))
-                    (insert ")\n")
-                    (write-region (point-min) (point-max) file-elisp
-                                  nil 'silent)))
-		(write-region (concat file-data "\n") nil
-                              (expand-file-name smtpmail-queue-index-file
-                                                smtpmail-queue-dir)
-                              t 'silent))
-	      (kill-buffer buffer-data))))
-      (kill-buffer tembuf)
-      (if (bufferp errbuf)
-	  (kill-buffer errbuf)))))
+        (let ((smtpmail-code-conv-from
+	       (if enable-multibyte-characters
+	           (let ((sendmail-coding-system smtpmail-code-conv-from))
+	             (select-message-coding-system)))))
+          (smtpmail-prepare-mail tembuf smtpmail-code-conv-from)
+          (if smtpmail-queue-mail
+              (smtpmail-queue-mail tembuf smtpmail-code-conv-from)
+            (smtpmail-send-mail tembuf)))
+      (kill-buffer tembuf))))
 
 ;;;###autoload
 (defun smtpmail-send-queued-mail ()
-- 
2.40.0


[-- Attachment #3: Type: text/plain, Size: 18 bytes --]

-- 
Manuel Giraud

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-05-06  6:20     ` Eli Zaretskii
  2023-05-06  9:34       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-05-09  9:52       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-10 11:47         ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-09  9:52 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

[-- Attachment #1: Type: text/plain, Size: 86 bytes --]

Hi,

I forgot to "declare" 'result' in smtpmail-send-it.  Here is an updated
version.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-smtpmail-send-it-split.patch --]
[-- Type: text/x-patch, Size: 18301 bytes --]

From a7786a443abebe38acd968dcd7ea2c2f2364d4a0 Mon Sep 17 00:00:00 2001
From: Manuel Giraud <manuel@ledu-giraud.fr>
Date: Fri, 5 May 2023 14:35:01 +0200
Subject: [PATCH] smtpmail-send-it split

* lisp/mail/smtpmail.el (smtpmail-prepare-mail): New function that
prepares the mail with current buffer content.
(smtpmail-queue-mail): New function to queue a mail (prepared by
'smtpmail-prepare-mail').
(smtpmail-send-mail): New function to send a mail (prepared by
'smtpmail-send-mail').
(smtpmail-send-it): Use all three previous functions.  While here,
remove 'errbuf' leftovers.
---
 lisp/mail/smtpmail.el | 412 +++++++++++++++++++++---------------------
 1 file changed, 205 insertions(+), 207 deletions(-)

diff --git a/lisp/mail/smtpmail.el b/lisp/mail/smtpmail.el
index 78688d170cc..714f1e14eaf 100644
--- a/lisp/mail/smtpmail.el
+++ b/lisp/mail/smtpmail.el
@@ -205,217 +205,215 @@ smtpmail-mail-address
   "Value to use for envelope-from address for mail from ambient buffer.")
 
 ;;; Functions
+(defun smtpmail-prepare-mail (tembuf smtpmail-code-conv-from)
+    (let ((case-fold-search nil)
+	  delimline
+	  (mailbuf (current-buffer))
+         ;; Examine this variable now, so that
+	 ;; local binding in the mail buffer will take effect.
+	 (smtpmail-mail-address
+          (save-restriction
+            ;; Only look at the headers when fetching the
+            ;; envelope address.
+            (message-narrow-to-headers)
+            (or (and mail-specify-envelope-from (mail-envelope-from))
+                (let ((from (mail-fetch-field "from")))
+	          (and from
+		       (cadr (mail-extract-address-components from))))
+	        (smtpmail-user-mail-address)))))
+    (with-current-buffer tembuf
+      (erase-buffer)
+      ;; Use the same `buffer-file-coding-system' as in the mail
+      ;; buffer, otherwise any `write-region' invocations (e.g., in
+      ;; mail-do-fcc below) will annoy with asking for a suitable
+      ;; encoding.
+      (set-buffer-file-coding-system smtpmail-code-conv-from nil t)
+      (insert-buffer-substring mailbuf)
+      (goto-char (point-max))
+      ;; require one newline at the end.
+      (or (= (preceding-char) ?\n)
+	  (insert ?\n))
+      ;; Change header-delimiter to be what sendmail expects.
+      (mail-sendmail-undelimit-header)
+      (setq delimline (point-marker))
+      (if mail-aliases
+	  (expand-mail-aliases (point-min) delimline))
+      (goto-char (point-min))
+      ;; ignore any blank lines in the header
+      (while (and (re-search-forward "\n\n\n*" delimline t)
+		  (< (point) delimline))
+	(replace-match "\n"))
+      (let ((case-fold-search t))
+	;; We used to process Resent-... headers here,
+	;; but it was not done properly, and the job
+	;; is done correctly in `smtpmail-deduce-address-list'.
+	;; Don't send out a blank subject line
+	(goto-char (point-min))
+	(if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t)
+	    (replace-match "")
+	  ;; This one matches a Subject just before the header delimiter.
+	  (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t)
+		   (= (match-end 0) delimline))
+	      (replace-match "")))
+	;; Put the "From:" field in unless for some odd reason
+	;; they put one in themselves.
+	(goto-char (point-min))
+	(if (not (re-search-forward "^From:" delimline t))
+	    (let* ((login smtpmail-mail-address)
+		   (fullname (user-full-name)))
+	      (cond ((eq mail-from-style 'angles)
+		     (insert "From: " fullname)
+		     (let ((fullname-start (+ (point-min) 6))
+			   (fullname-end (point-marker)))
+		       (goto-char fullname-start)
+		       ;; Look for a character that cannot appear unquoted
+		       ;; according to RFC 822 or its successors.
+		       (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]"
+					      fullname-end 1)
+			   (progn
+			     ;; Quote fullname, escaping specials.
+			     (goto-char fullname-start)
+			     (insert "\"")
+			     (while (re-search-forward "[\"\\]"
+						       fullname-end 1)
+			       (replace-match "\\\\\\&" t))
+			     (insert "\""))))
+		     (insert " <" login ">\n"))
+		    ((eq mail-from-style 'parens)
+		     (insert "From: " login " (")
+		     (let ((fullname-start (point)))
+		       (insert fullname)
+		       (let ((fullname-end (point-marker)))
+			 (goto-char fullname-start)
+			 ;; RFC 822 and its successors say \ and
+			 ;; nonmatching parentheses must be
+			 ;; escaped in comments.
+			 ;; Escape every instance of ()\ ...
+			 (while (re-search-forward "[()\\]" fullname-end 1)
+			   (replace-match "\\\\\\&" t))
+			 ;; ... then undo escaping of matching parentheses,
+			 ;; including matching nested parentheses.
+			 (goto-char fullname-start)
+			 (while (re-search-forward
+				 "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
+				 fullname-end 1)
+			   (replace-match "\\1(\\3)" t)
+			   (goto-char fullname-start))))
+		     (insert ")\n"))
+		    ((null mail-from-style)
+		     (insert "From: " login "\n")))))
+	;; Insert a `Message-Id:' field if there isn't one yet.
+	(goto-char (point-min))
+	(unless (re-search-forward "^Message-Id:" delimline t)
+	  (insert "Message-Id: " (message-make-message-id) "\n"))
+	;; Insert a `Date:' field if there isn't one yet.
+	(goto-char (point-min))
+	(unless (re-search-forward "^Date:" delimline t)
+	  (insert "Date: " (message-make-date) "\n"))
+	;; Possibly add a MIME header for the current coding system
+	(let (charset)
+	  (goto-char (point-min))
+	  (and (eq mail-send-nonascii 'mime)
+	       (not (re-search-forward "^MIME-version:" delimline t))
+	       (progn (skip-chars-forward "\0-\177")
+		      (/= (point) (point-max)))
+	       smtpmail-code-conv-from
+	       (setq charset
+		     (coding-system-get smtpmail-code-conv-from
+					'mime-charset))
+	       (goto-char delimline)
+	       (insert "MIME-version: 1.0\n"
+		       "Content-type: text/plain; charset="
+		       (symbol-name charset)
+		       "\nContent-Transfer-Encoding: 8bit\n")))
+	;; Insert an extra newline if we need it to work around
+	;; Sun's bug that swallows newlines.
+	(goto-char (1+ delimline))
+	;; Find and handle any Fcc fields.
+	(goto-char (point-min))
+	(if (re-search-forward "^Fcc:" delimline t)
+	    ;; Force `mail-do-fcc' to use the encoding of the mail
+	    ;; buffer to encode outgoing messages on Fcc files.
+	    (let ((coding-system-for-write
+		   ;; mbox files must have Unix EOLs.
+		   (coding-system-change-eol-conversion
+		    smtpmail-code-conv-from 'unix)))
+	      (mail-do-fcc delimline))))
+      ;; Encode the header according to RFC2047.
+      (mail-encode-header (point-min) delimline)
+      ;;
+      (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*"))
+      (setq smtpmail-recipient-address-list
+            (smtpmail-deduce-address-list tembuf (point-min) delimline))
+      (kill-buffer smtpmail-address-buffer)
+
+      (smtpmail-do-bcc delimline))))
+
+(defun smtpmail-queue-mail (tembuf smtpmail-code-conv-from)
+  (let* ((file-data
+	  (expand-file-name
+	   (format "%s_%i"
+		   (format-time-string "%Y-%m-%d_%H:%M:%S")
+		   (setq smtpmail-queue-counter
+			 (1+ smtpmail-queue-counter)))
+	   smtpmail-queue-dir))
+	 (file-data (convert-standard-filename file-data))
+	 (file-elisp (concat file-data ".el"))
+	 (buffer-data (create-file-buffer file-data)))
+    (unless (file-exists-p smtpmail-queue-dir)
+      (make-directory smtpmail-queue-dir t))
+    (with-current-buffer buffer-data
+      (erase-buffer)
+      (set-buffer-file-coding-system
+       ;; We will be reading the file with no-conversion in
+       ;; smtpmail-send-queued-mail below, so write it out
+       ;; with Unix EOLs.
+       (coding-system-change-eol-conversion
+	(or smtpmail-code-conv-from 'undecided)
+	'unix)
+       nil t)
+      (insert-buffer-substring tembuf)
+      (write-file file-data)
+      (let ((coding-system-for-write 'utf-8))
+        (with-temp-buffer
+          (insert "(setq ")
+          (dolist (var (cons 'smtpmail-recipient-address-list
+                             ;; Perhaps store the server etc.
+                             (and smtpmail-store-queue-variables
+                                  smtpmail--stored-queue-variables)))
+            (insert (format "     %s %S\n" var (symbol-value var))))
+          (insert ")\n")
+          (write-region (point-min) (point-max) file-elisp
+                        nil 'silent)))
+      (write-region (concat file-data "\n") nil
+                    (expand-file-name smtpmail-queue-index-file
+                                      smtpmail-queue-dir)
+                    t 'silent))
+    (kill-buffer buffer-data)))
+
+(defun smtpmail-send-mail (tembuf)
+  (let (result)
+    (if (not (null smtpmail-recipient-address-list))
+        (when (setq result
+                    (smtpmail-via-smtp
+                     smtpmail-recipient-address-list tembuf))
+          (error "Sending failed: %s"
+                 (smtpmail--sanitize-error-message result)))
+      (error "Sending failed; no recipients"))))
 
 ;;;###autoload
 (defun smtpmail-send-it ()
-  (let ((errbuf (if mail-interactive
-		    (generate-new-buffer " smtpmail errors")
-		  0))
-	(tembuf (generate-new-buffer " smtpmail temp"))
-	(case-fold-search nil)
-	delimline
-	result
-	(mailbuf (current-buffer))
-        ;; Examine this variable now, so that
-	;; local binding in the mail buffer will take effect.
-	(smtpmail-mail-address
-         (save-restriction
-           ;; Only look at the headers when fetching the
-           ;; envelope address.
-           (message-narrow-to-headers)
-           (or (and mail-specify-envelope-from (mail-envelope-from))
-               (let ((from (mail-fetch-field "from")))
-	         (and from
-		      (cadr (mail-extract-address-components from))))
-	       (smtpmail-user-mail-address))))
-	(smtpmail-code-conv-from
-	 (if enable-multibyte-characters
-	     (let ((sendmail-coding-system smtpmail-code-conv-from))
-	       (select-message-coding-system)))))
+  (let ((tembuf (generate-new-buffer " smtpmail temp")))
     (unwind-protect
-	(with-current-buffer tembuf
-	  (erase-buffer)
-	  ;; Use the same `buffer-file-coding-system' as in the mail
-	  ;; buffer, otherwise any `write-region' invocations (e.g., in
-	  ;; mail-do-fcc below) will annoy with asking for a suitable
-	  ;; encoding.
-	  (set-buffer-file-coding-system smtpmail-code-conv-from nil t)
-	  (insert-buffer-substring mailbuf)
-	  (goto-char (point-max))
-	  ;; require one newline at the end.
-	  (or (= (preceding-char) ?\n)
-	      (insert ?\n))
-	  ;; Change header-delimiter to be what sendmail expects.
-	  (mail-sendmail-undelimit-header)
-	  (setq delimline (point-marker))
-          ;; (sendmail-synch-aliases)
-	  (if mail-aliases
-	      (expand-mail-aliases (point-min) delimline))
-	  (goto-char (point-min))
-	  ;; ignore any blank lines in the header
-	  (while (and (re-search-forward "\n\n\n*" delimline t)
-		      (< (point) delimline))
-	    (replace-match "\n"))
-	  (let ((case-fold-search t))
-	    ;; We used to process Resent-... headers here,
-	    ;; but it was not done properly, and the job
-	    ;; is done correctly in `smtpmail-deduce-address-list'.
-	    ;; Don't send out a blank subject line
-	    (goto-char (point-min))
-	    (if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t)
-		(replace-match "")
-	      ;; This one matches a Subject just before the header delimiter.
-	      (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t)
-		       (= (match-end 0) delimline))
-		  (replace-match "")))
-	    ;; Put the "From:" field in unless for some odd reason
-	    ;; they put one in themselves.
-	    (goto-char (point-min))
-	    (if (not (re-search-forward "^From:" delimline t))
-		(let* ((login smtpmail-mail-address)
-		       (fullname (user-full-name)))
-		  (cond ((eq mail-from-style 'angles)
-			 (insert "From: " fullname)
-			 (let ((fullname-start (+ (point-min) 6))
-			       (fullname-end (point-marker)))
-			   (goto-char fullname-start)
-			   ;; Look for a character that cannot appear unquoted
-			   ;; according to RFC 822 or its successors.
-			   (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]"
-						  fullname-end 1)
-			       (progn
-				 ;; Quote fullname, escaping specials.
-				 (goto-char fullname-start)
-				 (insert "\"")
-				 (while (re-search-forward "[\"\\]"
-							   fullname-end 1)
-				   (replace-match "\\\\\\&" t))
-				 (insert "\""))))
-			 (insert " <" login ">\n"))
-			((eq mail-from-style 'parens)
-			 (insert "From: " login " (")
-			 (let ((fullname-start (point)))
-			   (insert fullname)
-			   (let ((fullname-end (point-marker)))
-			     (goto-char fullname-start)
-			     ;; RFC 822 and its successors say \ and
-			     ;; nonmatching parentheses must be
-			     ;; escaped in comments.
-			     ;; Escape every instance of ()\ ...
-			     (while (re-search-forward "[()\\]" fullname-end 1)
-			       (replace-match "\\\\\\&" t))
-			     ;; ... then undo escaping of matching parentheses,
-			     ;; including matching nested parentheses.
-			     (goto-char fullname-start)
-			     (while (re-search-forward
-				     "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
-				     fullname-end 1)
-			       (replace-match "\\1(\\3)" t)
-			       (goto-char fullname-start))))
-			 (insert ")\n"))
-			((null mail-from-style)
-			 (insert "From: " login "\n")))))
-	    ;; Insert a `Message-Id:' field if there isn't one yet.
-	    (goto-char (point-min))
-	    (unless (re-search-forward "^Message-Id:" delimline t)
-	      (insert "Message-Id: " (message-make-message-id) "\n"))
-	    ;; Insert a `Date:' field if there isn't one yet.
-	    (goto-char (point-min))
-	    (unless (re-search-forward "^Date:" delimline t)
-	      (insert "Date: " (message-make-date) "\n"))
-	    ;; Possibly add a MIME header for the current coding system
-	    (let (charset)
-	      (goto-char (point-min))
-	      (and (eq mail-send-nonascii 'mime)
-		   (not (re-search-forward "^MIME-version:" delimline t))
-		   (progn (skip-chars-forward "\0-\177")
-			  (/= (point) (point-max)))
-		   smtpmail-code-conv-from
-		   (setq charset
-			 (coding-system-get smtpmail-code-conv-from
-					    'mime-charset))
-		   (goto-char delimline)
-		   (insert "MIME-version: 1.0\n"
-			   "Content-type: text/plain; charset="
-			   (symbol-name charset)
-			   "\nContent-Transfer-Encoding: 8bit\n")))
-	    ;; Insert an extra newline if we need it to work around
-	    ;; Sun's bug that swallows newlines.
-	    (goto-char (1+ delimline))
-	    ;; Find and handle any Fcc fields.
-	    (goto-char (point-min))
-	    (if (re-search-forward "^Fcc:" delimline t)
-		;; Force `mail-do-fcc' to use the encoding of the mail
-		;; buffer to encode outgoing messages on Fcc files.
-		(let ((coding-system-for-write
-		       ;; mbox files must have Unix EOLs.
-		       (coding-system-change-eol-conversion
-			smtpmail-code-conv-from 'unix)))
-		  (mail-do-fcc delimline)))
-	    (if mail-interactive
-		(with-current-buffer errbuf
-		  (erase-buffer))))
-	  ;; Encode the header according to RFC2047.
-	  (mail-encode-header (point-min) delimline)
-	  ;;
-	  (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*"))
-	  (setq smtpmail-recipient-address-list
-                (smtpmail-deduce-address-list tembuf (point-min) delimline))
-	  (kill-buffer smtpmail-address-buffer)
-
-	  (smtpmail-do-bcc delimline)
-          ;; Send or queue
-	  (if (not smtpmail-queue-mail)
-	      (if (not (null smtpmail-recipient-address-list))
-		  (when (setq result
-			      (smtpmail-via-smtp
-			       smtpmail-recipient-address-list tembuf))
-		    (error "Sending failed: %s"
-                           (smtpmail--sanitize-error-message result)))
-		(error "Sending failed; no recipients"))
-	    (let* ((file-data
-		    (expand-file-name
-		     (format "%s_%i"
-			     (format-time-string "%Y-%m-%d_%H:%M:%S")
-			     (setq smtpmail-queue-counter
-				   (1+ smtpmail-queue-counter)))
-		     smtpmail-queue-dir))
-		   (file-data (convert-standard-filename file-data))
-		   (file-elisp (concat file-data ".el"))
-		   (buffer-data (create-file-buffer file-data)))
-	      (unless (file-exists-p smtpmail-queue-dir)
-		(make-directory smtpmail-queue-dir t))
-	      (with-current-buffer buffer-data
-		(erase-buffer)
-		(set-buffer-file-coding-system
-		 ;; We will be reading the file with no-conversion in
-		 ;; smtpmail-send-queued-mail below, so write it out
-		 ;; with Unix EOLs.
-		 (coding-system-change-eol-conversion
-		  (or smtpmail-code-conv-from 'undecided)
-		  'unix)
-		 nil t)
-		(insert-buffer-substring tembuf)
-		(write-file file-data)
-                (let ((coding-system-for-write 'utf-8))
-                  (with-temp-buffer
-                    (insert "(setq ")
-                    (dolist (var (cons 'smtpmail-recipient-address-list
-                                       ;; Perhaps store the server etc.
-                                       (and smtpmail-store-queue-variables
-                                            smtpmail--stored-queue-variables)))
-                      (insert (format "     %s %S\n" var (symbol-value var))))
-                    (insert ")\n")
-                    (write-region (point-min) (point-max) file-elisp
-                                  nil 'silent)))
-		(write-region (concat file-data "\n") nil
-                              (expand-file-name smtpmail-queue-index-file
-                                                smtpmail-queue-dir)
-                              t 'silent))
-	      (kill-buffer buffer-data))))
-      (kill-buffer tembuf)
-      (if (bufferp errbuf)
-	  (kill-buffer errbuf)))))
+        (let ((smtpmail-code-conv-from
+	       (if enable-multibyte-characters
+	           (let ((sendmail-coding-system smtpmail-code-conv-from))
+	             (select-message-coding-system)))))
+          (smtpmail-prepare-mail tembuf smtpmail-code-conv-from)
+          (if smtpmail-queue-mail
+              (smtpmail-queue-mail tembuf smtpmail-code-conv-from)
+            (smtpmail-send-mail tembuf)))
+      (kill-buffer tembuf))))
 
 ;;;###autoload
 (defun smtpmail-send-queued-mail ()
-- 
2.40.0


[-- Attachment #3: Type: text/plain, Size: 18 bytes --]

-- 
Manuel Giraud

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-05-09  9:52       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-05-10 11:47         ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-11 13:28           ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-10 11:47 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Hi Eli,

My strategy after the previous patch is summed up by this function:

--8<---------------cut here---------------start------------->8---
(defun smtpmail-async-send-it (cleanups)
  (let ((tembuf (generate-new-buffer " smtpmail temp"))
        (smtpmail-code-conv-from
	       (if enable-multibyte-characters
	           (let ((sendmail-coding-system smtpmail-code-conv-from))
	             (select-message-coding-system)))))
    (smtpmail-prepare-mail tembuf smtpmail-code-conv-from)
    (push #'(lambda () (kill-buffer tembuf)) cleanups)
    (make-thread #'(lambda ()
                     (smtpmail-send-mail tembuf)
                     (mapc #'funcall cleanups)))))
--8<---------------cut here---------------end--------------->8---

That is, I'd like carry around a 'cleanups' list that holds all the
functions that needed to be called after the mail was sent.

I then need to propagate this 'cleanups' parameter to callers of
'smtpmail-send-it'.  The problem is that encounter code with the
following form:

--8<---------------cut here---------------start------------->8---
(unwind-protect
    (let (haha)
      (do)
      (many)
      (things)
      (smtpmail-send-it-or-one-of-its-caller)
      (run)
      (other)
      (stuff))
  (kill-some-top-level-buffer))
--8<---------------cut here---------------end--------------->8---

I'm tempted to put '(run)(other)(stuff)(kill-some-top-level-buffer)'
into the cleanups list and remove the unwind-protect but then if
something goes wrong before sending the mail the
'(kill-some-top-level-buffer)' part won't be called.  OTOH, if I let the
'(unwind-protect…  (kill-some-top-level-buffer)' in place I could shoot
myself in the foot with the code that use this buffer into the thread.

So I guess, my question is how does one mix Lisp thread with
unwind-protect?

Best regards,
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-05-10 11:47         ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-05-11 13:28           ` Eli Zaretskii
  2023-05-11 20:59             ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-05-11 13:28 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Wed, 10 May 2023 13:47:11 +0200
> 
> So I guess, my question is how does one mix Lisp thread with
> unwind-protect?

I'm not sure I understand why you need to.  The two unwind-protect
handlers will run at different times and most probably will need to
unwind different stuff, although there could be overlap.  So why is it
a problem to have two separate unwind forms?





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-05-11 13:28           ` Eli Zaretskii
@ 2023-05-11 20:59             ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-12  5:41               ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-11 20:59 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Manuel Giraud <manuel@ledu-giraud.fr>
>> Cc: 63311@debbugs.gnu.org
>> Date: Wed, 10 May 2023 13:47:11 +0200
>> 
>> So I guess, my question is how does one mix Lisp thread with
>> unwind-protect?
>
> I'm not sure I understand why you need to.  The two unwind-protect
> handlers will run at different times and most probably will need to
> unwind different stuff, although there could be overlap.  So why is it
> a problem to have two separate unwind forms?

I was not talking about two separate unwind forms.  I was talking about
*thread* and unwind.  Here is a minimal example that exhibits my
problem:

--8<---------------cut here---------------start------------->8---
(setq-local lexical-binding t)

(defun my-problem ()
  (interactive)
  (let ((buf (generate-new-buffer "*foo*")))
    (with-current-buffer buf
      (insert "secret message"))
    (unwind-protect
	(make-thread #'(lambda ()
			 (with-current-buffer buf
			   (sit-for 10)
			   (message (buffer-string)))))
      (kill-buffer buf))))
--8<---------------cut here---------------end--------------->8---

The thread won't have a chance to do its job since the buffer will
already be dead.
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-05-11 20:59             ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-05-12  5:41               ` Eli Zaretskii
  2023-05-12  6:24                 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-05-12  5:41 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Thu, 11 May 2023 22:59:20 +0200
> 
> (defun my-problem ()
>   (interactive)
>   (let ((buf (generate-new-buffer "*foo*")))
>     (with-current-buffer buf
>       (insert "secret message"))
>     (unwind-protect
> 	(make-thread #'(lambda ()
> 			 (with-current-buffer buf
> 			   (sit-for 10)
> 			   (message (buffer-string)))))
>       (kill-buffer buf))))
> --8<---------------cut here---------------end--------------->8---
> 
> The thread won't have a chance to do its job since the buffer will
> already be dead.

Of course.  So you cannot do that, obviously.  Cleanup that gets in
the way of code you run in a thread must be done after thread-join
returns, or when thread-live-p returns nil for the thread.  Or use
some other synchronization method.  There could be several such
threads alive at the same time, btw.

In the unwind-protect handler of the main thread you can only do
cleanup of stuff that the thread doesn't need, or if you are sure the
thread was not started (due to some error that precludes the call to
make-thread).

I'm not aware of any other machinery we have for these cases.





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-05-12  5:41               ` Eli Zaretskii
@ 2023-05-12  6:24                 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-12  7:09                   ` Eli Zaretskii
  2023-05-12  7:10                   ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-12  6:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Manuel Giraud <manuel@ledu-giraud.fr>
>> Cc: 63311@debbugs.gnu.org
>> Date: Thu, 11 May 2023 22:59:20 +0200
>> 
>> (defun my-problem ()
>>   (interactive)
>>   (let ((buf (generate-new-buffer "*foo*")))
>>     (with-current-buffer buf
>>       (insert "secret message"))
>>     (unwind-protect
>> 	(make-thread #'(lambda ()
>> 			 (with-current-buffer buf
>> 			   (sit-for 10)
>> 			   (message (buffer-string)))))
>>       (kill-buffer buf))))
>> --8<---------------cut here---------------end--------------->8---
>> 
>> The thread won't have a chance to do its job since the buffer will
>> already be dead.
>
> Of course.  So you cannot do that, obviously.  Cleanup that gets in
> the way of code you run in a thread must be done after thread-join
> returns, or when thread-live-p returns nil for the thread.  Or use
> some other synchronization method.  There could be several such
> threads alive at the same time, btw.
>
> In the unwind-protect handler of the main thread you can only do
> cleanup of stuff that the thread doesn't need, or if you are sure the
> thread was not started (due to some error that precludes the call to
> make-thread).

Thanks!  So I could go with something like this:
--8<---------------cut here---------------start------------->8---
(setq-local lexical-binding t)

(defun eli-solution ()
  (interactive)
  (let ((buf (generate-new-buffer "*foo*")))
    (with-current-buffer buf
      (insert "secret message"))
    (let ((cleanup #'(lambda () (kill-buffer buf)))
	  thread)
      (unwind-protect
	  (setf thread (make-thread #'(lambda ()
					(with-current-buffer buf
					  (sit-for 10)
					  (message (buffer-string))
					  (funcall cleanup)))))
	(unless (thread-live-p thread)
	  (funcall cleanup))))))
--8<---------------cut here---------------end--------------->8---

BTW, do you know a more elisp way of defining a function than
"(let ((f #'(lambda…))))" form?
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-05-12  6:24                 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-05-12  7:09                   ` Eli Zaretskii
  2023-05-12  7:57                     ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-12  7:10                   ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-05-12  7:09 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Fri, 12 May 2023 08:24:36 +0200
> 
> (setq-local lexical-binding t)
> 
> (defun eli-solution ()
>   (interactive)
>   (let ((buf (generate-new-buffer "*foo*")))
>     (with-current-buffer buf
>       (insert "secret message"))
>     (let ((cleanup #'(lambda () (kill-buffer buf)))
> 	  thread)
>       (unwind-protect
> 	  (setf thread (make-thread #'(lambda ()
> 					(with-current-buffer buf
> 					  (sit-for 10)
> 					  (message (buffer-string))
> 					  (funcall cleanup)))))
> 	(unless (thread-live-p thread)
> 	  (funcall cleanup))))))

Yes, something like that.

> BTW, do you know a more elisp way of defining a function than
> "(let ((f #'(lambda…))))" form?

I'm not sure I understand: what's not ELisp'y about that?

And why not use defun instead?





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-05-12  6:24                 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-05-12  7:09                   ` Eli Zaretskii
@ 2023-05-12  7:10                   ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 41+ messages in thread
From: Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-12  7:10 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: Eli Zaretskii, 63311


Manuel Giraud via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org> writes:

> BTW, do you know a more elisp way of defining a function than
> "(let ((f #'(lambda…))))" form?

First of all, I believe you can always get rid of the function quote
because λ is a self-evaluating form.  Not quite sure if
`lexical-binding' makes a difference here though.

Option 1:

```emacs-lisp
(eval-when-compile (require 'cl-macs))
(cl-flet ((f (arg) 'expressions))
  (f arg))
```

Option 2:

```emacs-lisp
(eval-when-compile (require 'cl-macs))
(cl-letf (((symbol-function 'f)
           (lambda (arg) 'expression)))
  (f arg))
```

-- 
Best,


RY





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-05-12  7:09                   ` Eli Zaretskii
@ 2023-05-12  7:57                     ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-01 12:35                       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-12  7:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Eli Zaretskii <eliz@gnu.org> writes:

[...]

>> BTW, do you know a more elisp way of defining a function than
>> "(let ((f #'(lambda…))))" form?
>
> I'm not sure I understand: what's not ELisp'y about that?

I meant what is the most idiomatic.  As Ruijie Yu said, there is also
Common Lisp extensions that are cleaner but will also add a new
dependency into "smtpmail.el" and "message.el".

> And why not use defun instead?

I'll try that.
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-05-12  7:57                     ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-01 12:35                       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-01 12:59                         ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-01 12:35 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

[-- Attachment #1: Type: text/plain, Size: 233 bytes --]

Hi,

I'm reviving this old bug report because I think I have made some
progress.  Here is a new patch that tries to send mail asynchronously.
This seems to work for me but, of course, it needs testing, testing and
even more testing.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-smtpmail-send-it-split-and-async.patch --]
[-- Type: text/x-patch, Size: 18702 bytes --]

From 1c105e1c70d290bc4e7dfe8180d1a210daa76f05 Mon Sep 17 00:00:00 2001
From: Manuel Giraud <manuel@ledu-giraud.fr>
Date: Fri, 5 May 2023 14:35:01 +0200
Subject: [PATCH] smtpmail-send-it split and async

* lisp/mail/smtpmail.el (smtpmail-prepare-mail): New function
that prepares the mail with current buffer content.
(smtpmail-queue-mail): New function to queue a mail (prepared by
'smtpmail-prepare-mail').
(smtpmail-send-mail): New function to send a mail (prepared by
'smtpmail-send-mail').
(smtpmail-send-it): Use all three previous functions.  Use a
thread to async 'smtpmail-send-mail'.  While here, remove
'errbuf' leftovers.
---
 lisp/mail/smtpmail.el | 421 +++++++++++++++++++++---------------------
 1 file changed, 213 insertions(+), 208 deletions(-)

diff --git a/lisp/mail/smtpmail.el b/lisp/mail/smtpmail.el
index 78688d170cc..a69aa027c0a 100644
--- a/lisp/mail/smtpmail.el
+++ b/lisp/mail/smtpmail.el
@@ -205,217 +205,222 @@ smtpmail-mail-address
   "Value to use for envelope-from address for mail from ambient buffer.")
 
 ;;; Functions
+(defun smtpmail-prepare-mail (tembuf smtpmail-code-conv-from)
+    (let ((case-fold-search nil)
+	  delimline
+	  (mailbuf (current-buffer))
+         ;; Examine this variable now, so that
+	 ;; local binding in the mail buffer will take effect.
+	 (smtpmail-mail-address
+          (save-restriction
+            ;; Only look at the headers when fetching the
+            ;; envelope address.
+            (message-narrow-to-headers)
+            (or (and mail-specify-envelope-from (mail-envelope-from))
+                (let ((from (mail-fetch-field "from")))
+	          (and from
+		       (cadr (mail-extract-address-components from))))
+	        (smtpmail-user-mail-address)))))
+    (with-current-buffer tembuf
+      (erase-buffer)
+      ;; Use the same `buffer-file-coding-system' as in the mail
+      ;; buffer, otherwise any `write-region' invocations (e.g., in
+      ;; mail-do-fcc below) will annoy with asking for a suitable
+      ;; encoding.
+      (set-buffer-file-coding-system smtpmail-code-conv-from nil t)
+      (insert-buffer-substring mailbuf)
+      (goto-char (point-max))
+      ;; require one newline at the end.
+      (or (= (preceding-char) ?\n)
+	  (insert ?\n))
+      ;; Change header-delimiter to be what sendmail expects.
+      (mail-sendmail-undelimit-header)
+      (setq delimline (point-marker))
+      (if mail-aliases
+	  (expand-mail-aliases (point-min) delimline))
+      (goto-char (point-min))
+      ;; ignore any blank lines in the header
+      (while (and (re-search-forward "\n\n\n*" delimline t)
+		  (< (point) delimline))
+	(replace-match "\n"))
+      (let ((case-fold-search t))
+	;; We used to process Resent-... headers here,
+	;; but it was not done properly, and the job
+	;; is done correctly in `smtpmail-deduce-address-list'.
+	;; Don't send out a blank subject line
+	(goto-char (point-min))
+	(if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t)
+	    (replace-match "")
+	  ;; This one matches a Subject just before the header delimiter.
+	  (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t)
+		   (= (match-end 0) delimline))
+	      (replace-match "")))
+	;; Put the "From:" field in unless for some odd reason
+	;; they put one in themselves.
+	(goto-char (point-min))
+	(if (not (re-search-forward "^From:" delimline t))
+	    (let* ((login smtpmail-mail-address)
+		   (fullname (user-full-name)))
+	      (cond ((eq mail-from-style 'angles)
+		     (insert "From: " fullname)
+		     (let ((fullname-start (+ (point-min) 6))
+			   (fullname-end (point-marker)))
+		       (goto-char fullname-start)
+		       ;; Look for a character that cannot appear unquoted
+		       ;; according to RFC 822 or its successors.
+		       (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]"
+					      fullname-end 1)
+			   (progn
+			     ;; Quote fullname, escaping specials.
+			     (goto-char fullname-start)
+			     (insert "\"")
+			     (while (re-search-forward "[\"\\]"
+						       fullname-end 1)
+			       (replace-match "\\\\\\&" t))
+			     (insert "\""))))
+		     (insert " <" login ">\n"))
+		    ((eq mail-from-style 'parens)
+		     (insert "From: " login " (")
+		     (let ((fullname-start (point)))
+		       (insert fullname)
+		       (let ((fullname-end (point-marker)))
+			 (goto-char fullname-start)
+			 ;; RFC 822 and its successors say \ and
+			 ;; nonmatching parentheses must be
+			 ;; escaped in comments.
+			 ;; Escape every instance of ()\ ...
+			 (while (re-search-forward "[()\\]" fullname-end 1)
+			   (replace-match "\\\\\\&" t))
+			 ;; ... then undo escaping of matching parentheses,
+			 ;; including matching nested parentheses.
+			 (goto-char fullname-start)
+			 (while (re-search-forward
+				 "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
+				 fullname-end 1)
+			   (replace-match "\\1(\\3)" t)
+			   (goto-char fullname-start))))
+		     (insert ")\n"))
+		    ((null mail-from-style)
+		     (insert "From: " login "\n")))))
+	;; Insert a `Message-Id:' field if there isn't one yet.
+	(goto-char (point-min))
+	(unless (re-search-forward "^Message-Id:" delimline t)
+	  (insert "Message-Id: " (message-make-message-id) "\n"))
+	;; Insert a `Date:' field if there isn't one yet.
+	(goto-char (point-min))
+	(unless (re-search-forward "^Date:" delimline t)
+	  (insert "Date: " (message-make-date) "\n"))
+	;; Possibly add a MIME header for the current coding system
+	(let (charset)
+	  (goto-char (point-min))
+	  (and (eq mail-send-nonascii 'mime)
+	       (not (re-search-forward "^MIME-version:" delimline t))
+	       (progn (skip-chars-forward "\0-\177")
+		      (/= (point) (point-max)))
+	       smtpmail-code-conv-from
+	       (setq charset
+		     (coding-system-get smtpmail-code-conv-from
+					'mime-charset))
+	       (goto-char delimline)
+	       (insert "MIME-version: 1.0\n"
+		       "Content-type: text/plain; charset="
+		       (symbol-name charset)
+		       "\nContent-Transfer-Encoding: 8bit\n")))
+	;; Insert an extra newline if we need it to work around
+	;; Sun's bug that swallows newlines.
+	(goto-char (1+ delimline))
+	;; Find and handle any Fcc fields.
+	(goto-char (point-min))
+	(if (re-search-forward "^Fcc:" delimline t)
+	    ;; Force `mail-do-fcc' to use the encoding of the mail
+	    ;; buffer to encode outgoing messages on Fcc files.
+	    (let ((coding-system-for-write
+		   ;; mbox files must have Unix EOLs.
+		   (coding-system-change-eol-conversion
+		    smtpmail-code-conv-from 'unix)))
+	      (mail-do-fcc delimline))))
+      ;; Encode the header according to RFC2047.
+      (mail-encode-header (point-min) delimline)
+      ;;
+      (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*"))
+      (setq smtpmail-recipient-address-list
+            (smtpmail-deduce-address-list tembuf (point-min) delimline))
+      (kill-buffer smtpmail-address-buffer)
+
+      (smtpmail-do-bcc delimline))))
+
+(defun smtpmail-queue-mail (tembuf smtpmail-code-conv-from)
+  (let* ((file-data
+	  (expand-file-name
+	   (format "%s_%i"
+		   (format-time-string "%Y-%m-%d_%H:%M:%S")
+		   (setq smtpmail-queue-counter
+			 (1+ smtpmail-queue-counter)))
+	   smtpmail-queue-dir))
+	 (file-data (convert-standard-filename file-data))
+	 (file-elisp (concat file-data ".el"))
+	 (buffer-data (create-file-buffer file-data)))
+    (unless (file-exists-p smtpmail-queue-dir)
+      (make-directory smtpmail-queue-dir t))
+    (with-current-buffer buffer-data
+      (erase-buffer)
+      (set-buffer-file-coding-system
+       ;; We will be reading the file with no-conversion in
+       ;; smtpmail-send-queued-mail below, so write it out
+       ;; with Unix EOLs.
+       (coding-system-change-eol-conversion
+	(or smtpmail-code-conv-from 'undecided)
+	'unix)
+       nil t)
+      (insert-buffer-substring tembuf)
+      (write-file file-data)
+      (let ((coding-system-for-write 'utf-8))
+        (with-temp-buffer
+          (insert "(setq ")
+          (dolist (var (cons 'smtpmail-recipient-address-list
+                             ;; Perhaps store the server etc.
+                             (and smtpmail-store-queue-variables
+                                  smtpmail--stored-queue-variables)))
+            (insert (format "     %s %S\n" var (symbol-value var))))
+          (insert ")\n")
+          (write-region (point-min) (point-max) file-elisp
+                        nil 'silent)))
+      (write-region (concat file-data "\n") nil
+                    (expand-file-name smtpmail-queue-index-file
+                                      smtpmail-queue-dir)
+                    t 'silent))
+    (kill-buffer buffer-data)))
+
+(defun smtpmail-send-mail (tembuf)
+  (let (result)
+    (if (not (null smtpmail-recipient-address-list))
+        (when (setq result
+                    (smtpmail-via-smtp
+                     smtpmail-recipient-address-list tembuf))
+          (error "Sending failed: %s"
+                 (smtpmail--sanitize-error-message result)))
+      (error "Sending failed; no recipients"))))
 
 ;;;###autoload
 (defun smtpmail-send-it ()
-  (let ((errbuf (if mail-interactive
-		    (generate-new-buffer " smtpmail errors")
-		  0))
-	(tembuf (generate-new-buffer " smtpmail temp"))
-	(case-fold-search nil)
-	delimline
-	result
-	(mailbuf (current-buffer))
-        ;; Examine this variable now, so that
-	;; local binding in the mail buffer will take effect.
-	(smtpmail-mail-address
-         (save-restriction
-           ;; Only look at the headers when fetching the
-           ;; envelope address.
-           (message-narrow-to-headers)
-           (or (and mail-specify-envelope-from (mail-envelope-from))
-               (let ((from (mail-fetch-field "from")))
-	         (and from
-		      (cadr (mail-extract-address-components from))))
-	       (smtpmail-user-mail-address))))
-	(smtpmail-code-conv-from
-	 (if enable-multibyte-characters
-	     (let ((sendmail-coding-system smtpmail-code-conv-from))
-	       (select-message-coding-system)))))
-    (unwind-protect
-	(with-current-buffer tembuf
-	  (erase-buffer)
-	  ;; Use the same `buffer-file-coding-system' as in the mail
-	  ;; buffer, otherwise any `write-region' invocations (e.g., in
-	  ;; mail-do-fcc below) will annoy with asking for a suitable
-	  ;; encoding.
-	  (set-buffer-file-coding-system smtpmail-code-conv-from nil t)
-	  (insert-buffer-substring mailbuf)
-	  (goto-char (point-max))
-	  ;; require one newline at the end.
-	  (or (= (preceding-char) ?\n)
-	      (insert ?\n))
-	  ;; Change header-delimiter to be what sendmail expects.
-	  (mail-sendmail-undelimit-header)
-	  (setq delimline (point-marker))
-          ;; (sendmail-synch-aliases)
-	  (if mail-aliases
-	      (expand-mail-aliases (point-min) delimline))
-	  (goto-char (point-min))
-	  ;; ignore any blank lines in the header
-	  (while (and (re-search-forward "\n\n\n*" delimline t)
-		      (< (point) delimline))
-	    (replace-match "\n"))
-	  (let ((case-fold-search t))
-	    ;; We used to process Resent-... headers here,
-	    ;; but it was not done properly, and the job
-	    ;; is done correctly in `smtpmail-deduce-address-list'.
-	    ;; Don't send out a blank subject line
-	    (goto-char (point-min))
-	    (if (re-search-forward "^Subject:\\([ \t]*\n\\)+\\b" delimline t)
-		(replace-match "")
-	      ;; This one matches a Subject just before the header delimiter.
-	      (if (and (re-search-forward "^Subject:\\([ \t]*\n\\)+" delimline t)
-		       (= (match-end 0) delimline))
-		  (replace-match "")))
-	    ;; Put the "From:" field in unless for some odd reason
-	    ;; they put one in themselves.
-	    (goto-char (point-min))
-	    (if (not (re-search-forward "^From:" delimline t))
-		(let* ((login smtpmail-mail-address)
-		       (fullname (user-full-name)))
-		  (cond ((eq mail-from-style 'angles)
-			 (insert "From: " fullname)
-			 (let ((fullname-start (+ (point-min) 6))
-			       (fullname-end (point-marker)))
-			   (goto-char fullname-start)
-			   ;; Look for a character that cannot appear unquoted
-			   ;; according to RFC 822 or its successors.
-			   (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]"
-						  fullname-end 1)
-			       (progn
-				 ;; Quote fullname, escaping specials.
-				 (goto-char fullname-start)
-				 (insert "\"")
-				 (while (re-search-forward "[\"\\]"
-							   fullname-end 1)
-				   (replace-match "\\\\\\&" t))
-				 (insert "\""))))
-			 (insert " <" login ">\n"))
-			((eq mail-from-style 'parens)
-			 (insert "From: " login " (")
-			 (let ((fullname-start (point)))
-			   (insert fullname)
-			   (let ((fullname-end (point-marker)))
-			     (goto-char fullname-start)
-			     ;; RFC 822 and its successors say \ and
-			     ;; nonmatching parentheses must be
-			     ;; escaped in comments.
-			     ;; Escape every instance of ()\ ...
-			     (while (re-search-forward "[()\\]" fullname-end 1)
-			       (replace-match "\\\\\\&" t))
-			     ;; ... then undo escaping of matching parentheses,
-			     ;; including matching nested parentheses.
-			     (goto-char fullname-start)
-			     (while (re-search-forward
-				     "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
-				     fullname-end 1)
-			       (replace-match "\\1(\\3)" t)
-			       (goto-char fullname-start))))
-			 (insert ")\n"))
-			((null mail-from-style)
-			 (insert "From: " login "\n")))))
-	    ;; Insert a `Message-Id:' field if there isn't one yet.
-	    (goto-char (point-min))
-	    (unless (re-search-forward "^Message-Id:" delimline t)
-	      (insert "Message-Id: " (message-make-message-id) "\n"))
-	    ;; Insert a `Date:' field if there isn't one yet.
-	    (goto-char (point-min))
-	    (unless (re-search-forward "^Date:" delimline t)
-	      (insert "Date: " (message-make-date) "\n"))
-	    ;; Possibly add a MIME header for the current coding system
-	    (let (charset)
-	      (goto-char (point-min))
-	      (and (eq mail-send-nonascii 'mime)
-		   (not (re-search-forward "^MIME-version:" delimline t))
-		   (progn (skip-chars-forward "\0-\177")
-			  (/= (point) (point-max)))
-		   smtpmail-code-conv-from
-		   (setq charset
-			 (coding-system-get smtpmail-code-conv-from
-					    'mime-charset))
-		   (goto-char delimline)
-		   (insert "MIME-version: 1.0\n"
-			   "Content-type: text/plain; charset="
-			   (symbol-name charset)
-			   "\nContent-Transfer-Encoding: 8bit\n")))
-	    ;; Insert an extra newline if we need it to work around
-	    ;; Sun's bug that swallows newlines.
-	    (goto-char (1+ delimline))
-	    ;; Find and handle any Fcc fields.
-	    (goto-char (point-min))
-	    (if (re-search-forward "^Fcc:" delimline t)
-		;; Force `mail-do-fcc' to use the encoding of the mail
-		;; buffer to encode outgoing messages on Fcc files.
-		(let ((coding-system-for-write
-		       ;; mbox files must have Unix EOLs.
-		       (coding-system-change-eol-conversion
-			smtpmail-code-conv-from 'unix)))
-		  (mail-do-fcc delimline)))
-	    (if mail-interactive
-		(with-current-buffer errbuf
-		  (erase-buffer))))
-	  ;; Encode the header according to RFC2047.
-	  (mail-encode-header (point-min) delimline)
-	  ;;
-	  (setq smtpmail-address-buffer (generate-new-buffer "*smtp-mail*"))
-	  (setq smtpmail-recipient-address-list
-                (smtpmail-deduce-address-list tembuf (point-min) delimline))
-	  (kill-buffer smtpmail-address-buffer)
-
-	  (smtpmail-do-bcc delimline)
-          ;; Send or queue
-	  (if (not smtpmail-queue-mail)
-	      (if (not (null smtpmail-recipient-address-list))
-		  (when (setq result
-			      (smtpmail-via-smtp
-			       smtpmail-recipient-address-list tembuf))
-		    (error "Sending failed: %s"
-                           (smtpmail--sanitize-error-message result)))
-		(error "Sending failed; no recipients"))
-	    (let* ((file-data
-		    (expand-file-name
-		     (format "%s_%i"
-			     (format-time-string "%Y-%m-%d_%H:%M:%S")
-			     (setq smtpmail-queue-counter
-				   (1+ smtpmail-queue-counter)))
-		     smtpmail-queue-dir))
-		   (file-data (convert-standard-filename file-data))
-		   (file-elisp (concat file-data ".el"))
-		   (buffer-data (create-file-buffer file-data)))
-	      (unless (file-exists-p smtpmail-queue-dir)
-		(make-directory smtpmail-queue-dir t))
-	      (with-current-buffer buffer-data
-		(erase-buffer)
-		(set-buffer-file-coding-system
-		 ;; We will be reading the file with no-conversion in
-		 ;; smtpmail-send-queued-mail below, so write it out
-		 ;; with Unix EOLs.
-		 (coding-system-change-eol-conversion
-		  (or smtpmail-code-conv-from 'undecided)
-		  'unix)
-		 nil t)
-		(insert-buffer-substring tembuf)
-		(write-file file-data)
-                (let ((coding-system-for-write 'utf-8))
-                  (with-temp-buffer
-                    (insert "(setq ")
-                    (dolist (var (cons 'smtpmail-recipient-address-list
-                                       ;; Perhaps store the server etc.
-                                       (and smtpmail-store-queue-variables
-                                            smtpmail--stored-queue-variables)))
-                      (insert (format "     %s %S\n" var (symbol-value var))))
-                    (insert ")\n")
-                    (write-region (point-min) (point-max) file-elisp
-                                  nil 'silent)))
-		(write-region (concat file-data "\n") nil
-                              (expand-file-name smtpmail-queue-index-file
-                                                smtpmail-queue-dir)
-                              t 'silent))
-	      (kill-buffer buffer-data))))
-      (kill-buffer tembuf)
-      (if (bufferp errbuf)
-	  (kill-buffer errbuf)))))
+  (let ((tembuf (generate-new-buffer " smtpmail temp"))
+        (smtpmail-code-conv-from
+	   (if enable-multibyte-characters
+	       (let ((sendmail-coding-system smtpmail-code-conv-from))
+	         (select-message-coding-system)))))
+    (smtpmail-prepare-mail tembuf smtpmail-code-conv-from)
+    (cond (smtpmail-queue-mail
+           (smtpmail-queue-mail tembuf smtpmail-code-conv-from)
+           (kill-buffer tembuf))
+          (t
+           (let ((cleanup (lambda () (kill-buffer tembuf)))
+                 thread)
+             (unwind-protect
+                 (setf thread (make-thread (lambda ()
+                                             (smtpmail-send-mail tembuf)
+                                             (funcall cleanup))))
+               (unless (thread-live-p thread)
+                 (funcall cleanup))))))))
 
 ;;;###autoload
 (defun smtpmail-send-queued-mail ()
-- 
2.42.0


[-- Attachment #3: Type: text/plain, Size: 18 bytes --]

-- 
Manuel Giraud

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-01 12:35                       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-01 12:59                         ` Eli Zaretskii
  2023-11-01 18:06                           ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-01 12:59 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Wed, 01 Nov 2023 13:35:45 +0100
> 
> I'm reviving this old bug report because I think I have made some
> progress.  Here is a new patch that tries to send mail asynchronously.
> This seems to work for me but, of course, it needs testing, testing and
> even more testing.

Thank you for working on this.

I have several questions about it:

  . I'm not sure I understand how will the success/failure of sending
    be communicated back to the callers.  Currently, when the sending
    succeeds, there's a message in echo-area, and if the message was a
    reply, then Emacs marks the original message as "have been replied
    to".  How will this work with async sending?

  . What happens if sending fails for some reason?  It could be that
    the problem is detected by smtpmail itself, or it could be that
    some low-level code signals an error -- what happens in both
    cases?

  . With which MUA are you testing this?

  . What happens if another message is sent while the previous one is
    still being sent?

  . What did you try to do in Emacs while the message was being sent,
    and did you see any problems with the foreground responsiveness?
    For that matter, how long did it take for the background thread to
    send the message?  If that was short enough, like 1 sec or so, I
    suggest to test this with sending a larger message, like a message
    with a large attachment.  That's because the most important
    situation where async sending is valuable is when it takes a long
    time to send a message, either because it's a large message or
    because the connection is slow or unreliable.





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-01 12:59                         ` Eli Zaretskii
@ 2023-11-01 18:06                           ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-01 19:29                             ` Eli Zaretskii
  2023-11-03  2:31                             ` Richard Stallman
  0 siblings, 2 replies; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-01 18:06 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Manuel Giraud <manuel@ledu-giraud.fr>
>> Cc: 63311@debbugs.gnu.org
>> Date: Wed, 01 Nov 2023 13:35:45 +0100
>> 
>> I'm reviving this old bug report because I think I have made some
>> progress.  Here is a new patch that tries to send mail asynchronously.
>> This seems to work for me but, of course, it needs testing, testing and
>> even more testing.
>
> Thank you for working on this.
>
> I have several questions about it:
>
>   . I'm not sure I understand how will the success/failure of sending
>     be communicated back to the callers.  Currently, when the sending
>     succeeds, there's a message in echo-area, and if the message was a
>     reply, then Emacs marks the original message as "have been replied
>     to".  How will this work with async sending?

The progress and "Sending email done" still shows in echo-area and
*Messages* buffer but asynchronously.  As for the "have been replied
too" part, it happens right after 'C-c C-c' so a message that should
error later down the line will be named as "*sent reply...": this is a
problem.

>   . What happens if sending fails for some reason?  It could be that
>     the problem is detected by smtpmail itself, or it could be that
>     some low-level code signals an error -- what happens in both
>     cases?

Some errors should be handled in 'smtpmail-send-mail' and signal by
calling (error).  But other errors won't be.  For instance, I tried to
send a mail to a non existent address and I get no error whatsoever: the
buffer is also called "*sent ...*"

>   . With which MUA are you testing this?

I'm testing gnus and message-mode.

>   . What happens if another message is sent while the previous one is
>     still being sent?

That I have tested.  It works because the temporary buffer where
everything takes place is generated by 'generate-new-buffer' which
creates a unique name if needed.

>   . What did you try to do in Emacs while the message was being sent,
>     and did you see any problems with the foreground responsiveness?

I did not do some intensive usage just moving to other buffers.  I've
not seen any problem with responsiveness.

>     For that matter, how long did it take for the background thread to
>     send the message?  If that was short enough, like 1 sec or so, I
>     suggest to test this with sending a larger message, like a message
>     with a large attachment.  That's because the most important
>     situation where async sending is valuable is when it takes a long
>     time to send a message, either because it's a large message or
>     because the connection is slow or unreliable.

Yes I have tested with longer to send message otherwise I would not be
able to see the asynchronous process.
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-01 18:06                           ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-01 19:29                             ` Eli Zaretskii
  2023-11-01 19:55                               ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-03  2:31                             ` Richard Stallman
  1 sibling, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-01 19:29 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Wed, 01 Nov 2023 19:06:08 +0100
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >   . I'm not sure I understand how will the success/failure of sending
> >     be communicated back to the callers.  Currently, when the sending
> >     succeeds, there's a message in echo-area, and if the message was a
> >     reply, then Emacs marks the original message as "have been replied
> >     to".  How will this work with async sending?
> 
> The progress and "Sending email done" still shows in echo-area and
> *Messages* buffer but asynchronously.

What happens if the foreground Lisp program displays something in the
echo-area at that time?  I'm asking because I don't think it's a good
idea to show this from a background thread.

> >   . What happens if sending fails for some reason?  It could be that
> >     the problem is detected by smtpmail itself, or it could be that
> >     some low-level code signals an error -- what happens in both
> >     cases?
> 
> Some errors should be handled in 'smtpmail-send-mail' and signal by
> calling (error).  But other errors won't be.  For instance, I tried to
> send a mail to a non existent address and I get no error whatsoever: the
> buffer is also called "*sent ...*"

Signaling an error in a non-main thread causes the thread exit
silently, with the error stored in a variable, so something should be
done to show the error to the user.

> >   . What happens if another message is sent while the previous one is
> >     still being sent?
> 
> That I have tested.  It works because the temporary buffer where
> everything takes place is generated by 'generate-new-buffer' which
> creates a unique name if needed.

So you have several threads sending at the same time?  If so, what
happens with their errors and success messages?

> >     For that matter, how long did it take for the background thread to
> >     send the message?  If that was short enough, like 1 sec or so, I
> >     suggest to test this with sending a larger message, like a message
> >     with a large attachment.  That's because the most important
> >     situation where async sending is valuable is when it takes a long
> >     time to send a message, either because it's a large message or
> >     because the connection is slow or unreliable.
> 
> Yes I have tested with longer to send message otherwise I would not be
> able to see the asynchronous process.

If you don't see problems with responsiveness, this is encouraging.
IME, such problems happen quite frequently, for example if you type
during the time the background thread does its job.

Thanks.





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-01 19:29                             ` Eli Zaretskii
@ 2023-11-01 19:55                               ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-02  5:48                                 ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-01 19:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Manuel Giraud <manuel@ledu-giraud.fr>
>> Cc: 63311@debbugs.gnu.org
>> Date: Wed, 01 Nov 2023 19:06:08 +0100
>> 
>> Eli Zaretskii <eliz@gnu.org> writes:
>> 
>> >   . I'm not sure I understand how will the success/failure of sending
>> >     be communicated back to the callers.  Currently, when the sending
>> >     succeeds, there's a message in echo-area, and if the message was a
>> >     reply, then Emacs marks the original message as "have been replied
>> >     to".  How will this work with async sending?
>> 
>> The progress and "Sending email done" still shows in echo-area and
>> *Messages* buffer but asynchronously.
>
> What happens if the foreground Lisp program displays something in the
> echo-area at that time?  I'm asking because I don't think it's a good
> idea to show this from a background thread.

Sorry I did not test this.  But maybe when this starts working, we
should consider removing the progress report for large messages.

>> >   . What happens if sending fails for some reason?  It could be that
>> >     the problem is detected by smtpmail itself, or it could be that
>> >     some low-level code signals an error -- what happens in both
>> >     cases?
>> 
>> Some errors should be handled in 'smtpmail-send-mail' and signal by
>> calling (error).  But other errors won't be.  For instance, I tried to
>> send a mail to a non existent address and I get no error whatsoever: the
>> buffer is also called "*sent ...*"
>
> Signaling an error in a non-main thread causes the thread exit
> silently, with the error stored in a variable, so something should be
> done to show the error to the user.

Yes, I have seen that and just learn about 'thread-signal'.

>> >   . What happens if another message is sent while the previous one is
>> >     still being sent?
>> 
>> That I have tested.  It works because the temporary buffer where
>> everything takes place is generated by 'generate-new-buffer' which
>> creates a unique name if needed.
>
> So you have several threads sending at the same time?  If so, what
> happens with their errors and success messages?

Their was no errors because those sendings did not generate any.  The
success messages appeared in the *Messages* buffer.

>> >     For that matter, how long did it take for the background thread to
>> >     send the message?  If that was short enough, like 1 sec or so, I
>> >     suggest to test this with sending a larger message, like a message
>> >     with a large attachment.  That's because the most important
>> >     situation where async sending is valuable is when it takes a long
>> >     time to send a message, either because it's a large message or
>> >     because the connection is slow or unreliable.
>> 
>> Yes I have tested with longer to send message otherwise I would not be
>> able to see the asynchronous process.
>
> If you don't see problems with responsiveness, this is encouraging.
> IME, such problems happen quite frequently, for example if you type
> during the time the background thread does its job.

Yes this is just a start and should be tested on normal/regular usage.
As always, when I start working on this I rediscover that there is many
housekeeping done afterward by the 'smtpmail-send-it' callers (marking
as sent via mail,...): this should be taken into account too.  So it may
be encouraging but I think this is just a start.
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-01 19:55                               ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-02  5:48                                 ` Eli Zaretskii
  2023-11-02 10:44                                   ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-02  5:48 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Wed, 01 Nov 2023 20:55:37 +0100
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> The progress and "Sending email done" still shows in echo-area and
> >> *Messages* buffer but asynchronously.
> >
> > What happens if the foreground Lisp program displays something in the
> > echo-area at that time?  I'm asking because I don't think it's a good
> > idea to show this from a background thread.
> 
> Sorry I did not test this.  But maybe when this starts working, we
> should consider removing the progress report for large messages.

I think when messages are sent in the background, there should be a
different series of messages: one at the beginning, when the thread is
launched, and one when the thread exits.  Both of these should be
output by the main thread, not the thread which sends.  The sending
progress messages will not be shown, since they are mostly useless
anyway (if the user wants the sending to be in the background, it
generally means he/she doesn't care much about the progress, since
Emacs is not waiting for the sending to complete).  If we need more
detailed messages in some cases, we could have a special buffer which
the user could then view if needed.

> > So you have several threads sending at the same time?  If so, what
> > happens with their errors and success messages?
> 
> Their was no errors because those sendings did not generate any.  The
> success messages appeared in the *Messages* buffer.

One more reason to move the messages to the main thread, to avoid
threads "fighting" for the echo area.

> > If you don't see problems with responsiveness, this is encouraging.
> > IME, such problems happen quite frequently, for example if you type
> > during the time the background thread does its job.
> 
> Yes this is just a start and should be tested on normal/regular usage.
> As always, when I start working on this I rediscover that there is many
> housekeeping done afterward by the 'smtpmail-send-it' callers (marking
> as sent via mail,...): this should be taken into account too.  So it may
> be encouraging but I think this is just a start.

Right, thanks.

When this is available, I will probably become a heavy user of this
feature.  It should probably be an opt-in feature initially, so as to
let people try it without disrupting their production workflows too
much.





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-02  5:48                                 ` Eli Zaretskii
@ 2023-11-02 10:44                                   ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-02 11:26                                     ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-02 10:44 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Eli Zaretskii <eliz@gnu.org> writes:

[...]

> I think when messages are sent in the background, there should be a
> different series of messages: one at the beginning, when the thread is
> launched, and one when the thread exits.  Both of these should be
> output by the main thread, not the thread which sends.

I think this is feasible for the message when the thread is launch but
not for the final message: the main-thread would have to 'thread-join'
on the sending thread and we'll lose the asynchronous behaviour, no?

> The sending progress messages will not be shown, since they are mostly
> useless anyway (if the user wants the sending to be in the background,
> it generally means he/she doesn't care much about the progress, since
> Emacs is not waiting for the sending to complete).  If we need more
> detailed messages in some cases, we could have a special buffer which
> the user could then view if needed.

Ok.

[...]

> Right, thanks.
>
> When this is available, I will probably become a heavy user of this
> feature.  It should probably be an opt-in feature initially, so as to
> let people try it without disrupting their production workflows too
> much.

Yes, I think it should be opt-in.  But such an option will also have
ramifications in message.el, Gnus and surely more that I don't even know
about. (BTW, do you have an idea for a name for such option?)
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-02 10:44                                   ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-02 11:26                                     ` Eli Zaretskii
  2023-11-05 14:24                                       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-02 11:26 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Thu, 02 Nov 2023 11:44:40 +0100
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> [...]
> 
> > I think when messages are sent in the background, there should be a
> > different series of messages: one at the beginning, when the thread is
> > launched, and one when the thread exits.  Both of these should be
> > output by the main thread, not the thread which sends.
> 
> I think this is feasible for the message when the thread is launch but
> not for the final message: the main-thread would have to 'thread-join'
> on the sending thread and we'll lose the asynchronous behaviour, no?

That is not necessary.  The background thread could add the message to
some queue which the main thread could check from time to time.  Or
something similar.

> > When this is available, I will probably become a heavy user of this
> > feature.  It should probably be an opt-in feature initially, so as to
> > let people try it without disrupting their production workflows too
> > much.
> 
> Yes, I think it should be opt-in.  But such an option will also have
> ramifications in message.el, Gnus and surely more that I don't even know
> about.

Probably.  (Another client is sendmail.el.)

> (BTW, do you have an idea for a name for such option?)

smtpmail-send-message-in-background ?





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-01 18:06                           ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-01 19:29                             ` Eli Zaretskii
@ 2023-11-03  2:31                             ` Richard Stallman
  2023-11-03  7:18                               ` Eli Zaretskii
  1 sibling, 1 reply; 41+ messages in thread
From: Richard Stallman @ 2023-11-03  2:31 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: eliz, 63311

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > The progress and "Sending email done" still shows in echo-area and
  > *Messages* buffer but asynchronously.

I think that may prove confusing.  What happens if you send a message,
then edit the buffer and send again before that "done" message appears
for the first?  When the "done" message appears, can you tell which message
was sent?

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-03  2:31                             ` Richard Stallman
@ 2023-11-03  7:18                               ` Eli Zaretskii
  2023-11-03 13:49                                 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-03  7:18 UTC (permalink / raw)
  To: rms; +Cc: 63311, manuel

> From: Richard Stallman <rms@gnu.org>
> Cc: eliz@gnu.org, 63311@debbugs.gnu.org
> Date: Thu, 02 Nov 2023 22:31:35 -0400
> 
>   > The progress and "Sending email done" still shows in echo-area and
>   > *Messages* buffer but asynchronously.
> 
> I think that may prove confusing.  What happens if you send a message,
> then edit the buffer and send again before that "done" message appears
> for the first?  When the "done" message appears, can you tell which message
> was sent?

The messages should be displayed by the main thread when the sending
thread finishes sending.  And we probably need to rethink the text of
the messages, to identify the message that was sent.





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-03  7:18                               ` Eli Zaretskii
@ 2023-11-03 13:49                                 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-03 14:29                                   ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-03 13:49 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rms, 63311

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Richard Stallman <rms@gnu.org>
>> Cc: eliz@gnu.org, 63311@debbugs.gnu.org
>> Date: Thu, 02 Nov 2023 22:31:35 -0400
>> 
>>   > The progress and "Sending email done" still shows in echo-area and
>>   > *Messages* buffer but asynchronously.
>> 
>> I think that may prove confusing.  What happens if you send a message,
>> then edit the buffer and send again before that "done" message appears
>> for the first?  When the "done" message appears, can you tell which message
>> was sent?
>
> The messages should be displayed by the main thread when the sending
> thread finishes sending.  And we probably need to rethink the text of
> the messages, to identify the message that was sent.

Yes, of course.  But I think we could do that at the very end of this
work.
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-03 13:49                                 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-03 14:29                                   ` Eli Zaretskii
  0 siblings, 0 replies; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-03 14:29 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: rms, 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: rms@gnu.org,  63311@debbugs.gnu.org
> Date: Fri, 03 Nov 2023 14:49:40 +0100
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > The messages should be displayed by the main thread when the sending
> > thread finishes sending.  And we probably need to rethink the text of
> > the messages, to identify the message that was sent.
> 
> Yes, of course.  But I think we could do that at the very end of this
> work.

Agreed.





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-02 11:26                                     ` Eli Zaretskii
@ 2023-11-05 14:24                                       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-05 15:46                                         ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-05 14:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Hi Eli,

I'm still struggling with making 'smtpmail-send-it' async.  As I'm using
message.el, I'm trying to make it work here.  But message.el in written
in such way that it is quite hard to make it work with a threaded
'smtpmail-send-it' call.

And then, from a message buffer (with a quite large attachment), I've
just evaluted the following: (make-thread #'message-send)... and
everything went ok:
           - Emacs is still responsive: I could switch to other
             buffers, request the status of a VC handled file.
             
           - When the message is finally sent, the buffer is renamed
             accordingly and tagged as sent via mail.

So my question is this one: instead of making 'smtpmail-send-it'
threaded why not have a threaded version of toplevel commands (such as
'message-send')?  We could hopefully do the same for sendmail.el.  Of
course, we should have it as opt-in behind customs
(message-send-in-background and/or mail-send-in-background?)

As for when something goes wrong and we end up in an 'error' call, maybe
we should fix how 'error' behave inside a thread.  What am I missing?
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-05 14:24                                       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-05 15:46                                         ` Eli Zaretskii
  2023-11-05 16:12                                           ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-05 15:46 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Sun, 05 Nov 2023 15:24:50 +0100
> 
> Hi Eli,
> 
> I'm still struggling with making 'smtpmail-send-it' async.  As I'm using
> message.el, I'm trying to make it work here.  But message.el in written
> in such way that it is quite hard to make it work with a threaded
> 'smtpmail-send-it' call.
> 
> And then, from a message buffer (with a quite large attachment), I've
> just evaluted the following: (make-thread #'message-send)... and
> everything went ok:
>            - Emacs is still responsive: I could switch to other
>              buffers, request the status of a VC handled file.
>              
>            - When the message is finally sent, the buffer is renamed
>              accordingly and tagged as sent via mail.
> 
> So my question is this one: instead of making 'smtpmail-send-it'
> threaded why not have a threaded version of toplevel commands (such as
> 'message-send')?  We could hopefully do the same for sendmail.el.  Of
> course, we should have it as opt-in behind customs
> (message-send-in-background and/or mail-send-in-background?)
> 
> As for when something goes wrong and we end up in an 'error' call, maybe
> we should fix how 'error' behave inside a thread.  What am I missing?

Nothing, AFAIU.  Instead of making smtpmail-send-it optionally working
asynchronously, it should be perfectly valid to have a separate
function called, say, message-send-asynchronously, which would work
with background threads and implement the same protocol as the other
MUA's send-it functions do.





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-05 15:46                                         ` Eli Zaretskii
@ 2023-11-05 16:12                                           ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-05 16:17                                             ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-05 16:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Eli Zaretskii <eliz@gnu.org> writes:

[...]

>> As for when something goes wrong and we end up in an 'error' call, maybe
>> we should fix how 'error' behave inside a thread.  What am I missing?
>
> Nothing, AFAIU.  Instead of making smtpmail-send-it optionally working
> asynchronously, it should be perfectly valid to have a separate
> function called, say, message-send-asynchronously, which would work
> with background threads and implement the same protocol as the other
> MUA's send-it functions do.

Ok.  But there is still the case where any 'error' call from a thread
will end up in limbo, no?
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-05 16:12                                           ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-05 16:17                                             ` Eli Zaretskii
  2023-11-06 10:21                                               ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-05 16:17 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Sun, 05 Nov 2023 17:12:03 +0100
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > Nothing, AFAIU.  Instead of making smtpmail-send-it optionally working
> > asynchronously, it should be perfectly valid to have a separate
> > function called, say, message-send-asynchronously, which would work
> > with background threads and implement the same protocol as the other
> > MUA's send-it functions do.
> 
> Ok.  But there is still the case where any 'error' call from a thread
> will end up in limbo, no?

The caller will need to fetch it and display it.





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-05 16:17                                             ` Eli Zaretskii
@ 2023-11-06 10:21                                               ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-06 12:40                                                 ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-06 10:21 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Manuel Giraud <manuel@ledu-giraud.fr>
>> Cc: 63311@debbugs.gnu.org
>> Date: Sun, 05 Nov 2023 17:12:03 +0100
>> 
>> Eli Zaretskii <eliz@gnu.org> writes:
>> 
>> > Nothing, AFAIU.  Instead of making smtpmail-send-it optionally working
>> > asynchronously, it should be perfectly valid to have a separate
>> > function called, say, message-send-asynchronously, which would work
>> > with background threads and implement the same protocol as the other
>> > MUA's send-it functions do.
>> 
>> Ok.  But there is still the case where any 'error' call from a thread
>> will end up in limbo, no?
>
> The caller will need to fetch it and display it.

Yes but how would I do that.  My idea was to left much code unmodified
(with all 'error' calls in case something goes wrong).  But how the
'main-thread' could fetch these errors.
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-06 10:21                                               ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-06 12:40                                                 ` Eli Zaretskii
  2023-11-06 15:56                                                   ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-06 12:40 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Mon, 06 Nov 2023 11:21:23 +0100
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> Ok.  But there is still the case where any 'error' call from a thread
> >> will end up in limbo, no?
> >
> > The caller will need to fetch it and display it.
> 
> Yes but how would I do that.  My idea was to left much code unmodified
> (with all 'error' calls in case something goes wrong).  But how the
> 'main-thread' could fetch these errors.

Using thread-last-error, or at least that's what I had in mind.





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-06 12:40                                                 ` Eli Zaretskii
@ 2023-11-06 15:56                                                   ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-06 16:28                                                     ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-06 15:56 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Manuel Giraud <manuel@ledu-giraud.fr>
>> Cc: 63311@debbugs.gnu.org
>> Date: Mon, 06 Nov 2023 11:21:23 +0100
>> 
>> Eli Zaretskii <eliz@gnu.org> writes:
>> 
>> >> Ok.  But there is still the case where any 'error' call from a thread
>> >> will end up in limbo, no?
>> >
>> > The caller will need to fetch it and display it.
>> 
>> Yes but how would I do that.  My idea was to left much code unmodified
>> (with all 'error' calls in case something goes wrong).  But how the
>> 'main-thread' could fetch these errors.
>
> Using thread-last-error, or at least that's what I had in mind.

It seems that 'thread-last-error' is global for all threads of Emacs so
I don't it would work.  Doesn't a thread record its error status and
message?
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-06 15:56                                                   ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-06 16:28                                                     ` Eli Zaretskii
  2023-11-06 17:57                                                       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-06 16:28 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Mon, 06 Nov 2023 16:56:33 +0100
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> Yes but how would I do that.  My idea was to left much code unmodified
> >> (with all 'error' calls in case something goes wrong).  But how the
> >> 'main-thread' could fetch these errors.
> >
> > Using thread-last-error, or at least that's what I had in mind.
> 
> It seems that 'thread-last-error' is global for all threads of Emacs so
> I don't it would work.  Doesn't a thread record its error status and
> message?

Sorry, I don't understand what exactly you are asking and what you are
saying.

Yes, thread-last-error accesses a global storage, but I fail to see
how this is a problem: if the main thread fetches the error in a
timely fashion, it should still work.  And if, for some reason, this
is not good enough, we could come up with a more fine-grained
mechanism.  But first I'd like to see a description of a real problem
with the existing mechanism: after all, it isn't expected that every
single thread you launch will die due to an error, right?  So the
situation where a thread dies and we need to access its error should
be relatively rare, and a global resource could still be adequate.





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-06 16:28                                                     ` Eli Zaretskii
@ 2023-11-06 17:57                                                       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-06 19:21                                                         ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-06 17:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Manuel Giraud <manuel@ledu-giraud.fr>
>> Cc: 63311@debbugs.gnu.org
>> Date: Mon, 06 Nov 2023 16:56:33 +0100
>> 
>> Eli Zaretskii <eliz@gnu.org> writes:
>> 
>> >> Yes but how would I do that.  My idea was to left much code unmodified
>> >> (with all 'error' calls in case something goes wrong).  But how the
>> >> 'main-thread' could fetch these errors.
>> >
>> > Using thread-last-error, or at least that's what I had in mind.
>> 
>> It seems that 'thread-last-error' is global for all threads of Emacs so
>> I don't it would work.  Doesn't a thread record its error status and
>> message?
>
> Sorry, I don't understand what exactly you are asking and what you are
> saying.
>
> Yes, thread-last-error accesses a global storage, but I fail to see
> how this is a problem: if the main thread fetches the error in a
> timely fashion, it should still work.  And if, for some reason, this
> is not good enough, we could come up with a more fine-grained
> mechanism.  But first I'd like to see a description of a real problem
> with the existing mechanism: after all, it isn't expected that every
> single thread you launch will die due to an error, right?  So the
> situation where a thread dies and we need to access its error should
> be relatively rare, and a global resource could still be adequate.

So just for recap, the idea is to have a command
('message-send-asynchronously' as you suggested) that will just be
wrapper around 'message-send' and creates a thread to send the current
buffer.  Such a thread could be stored in a list and, by mean of a
timer, the main-thread would sometimes look if this thread is dead.

If it is dead and (thread-last-error) returns nil maybe we can conclude
that everything went well.  But if (thread-last-error) returns a
message, it could be message from any other Emacs thread: what to do in
such case?  Or worse: the thread is dead, (thread-last-error) returns
nil... but it was cleared from another part of Emacs.
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-06 17:57                                                       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-06 19:21                                                         ` Eli Zaretskii
  2023-11-06 20:55                                                           ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-06 19:21 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Mon, 06 Nov 2023 18:57:59 +0100
> 
> So just for recap, the idea is to have a command
> ('message-send-asynchronously' as you suggested) that will just be
> wrapper around 'message-send' and creates a thread to send the current
> buffer.  Such a thread could be stored in a list and, by mean of a
> timer, the main-thread would sometimes look if this thread is dead.

Something like that, yes.

> If it is dead and (thread-last-error) returns nil maybe we can conclude
> that everything went well.  But if (thread-last-error) returns a
> message, it could be message from any other Emacs thread: what to do in
> such case?

Display a message about the error.

> Or worse: the thread is dead, (thread-last-error) returns
> nil... but it was cleared from another part of Emacs.

This means it exited successfully.  We could also maintain a data
structure where successfully-exiting threads will leave their success
status together with some id of the message they sent -- unlike a
thread that dies abruptly due to an error, a successful thread can
store the information in the data structure before exiting.





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-06 19:21                                                         ` Eli Zaretskii
@ 2023-11-06 20:55                                                           ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-07  3:26                                                             ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-06 20:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Eli Zaretskii <eliz@gnu.org> writes:

>> If it is dead and (thread-last-error) returns nil maybe we can conclude
>> that everything went well.  But if (thread-last-error) returns a
>> message, it could be message from any other Emacs thread: what to do in
>> such case?
>
> Display a message about the error.

I mean, the last error message could come from another thread not
related in anyway to mail sending.  No?

>> Or worse: the thread is dead, (thread-last-error) returns
>> nil... but it was cleared from another part of Emacs.
>
> This means it exited successfully.  We could also maintain a data
> structure where successfully-exiting threads will leave their success
> status together with some id of the message they sent -- unlike a
> thread that dies abruptly due to an error, a successful thread can
> store the information in the data structure before exiting.

Yes why not but then I'd have to modify internals of 'message-send':
something I thought I could escape.
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-06 20:55                                                           ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-07  3:26                                                             ` Eli Zaretskii
  2023-11-07  9:06                                                               ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-07  3:26 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Mon, 06 Nov 2023 21:55:49 +0100
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> If it is dead and (thread-last-error) returns nil maybe we can conclude
> >> that everything went well.  But if (thread-last-error) returns a
> >> message, it could be message from any other Emacs thread: what to do in
> >> such case?
> >
> > Display a message about the error.
> 
> I mean, the last error message could come from another thread not
> related in anyway to mail sending.  No?

It could, but why would there be other threads in this case?

> >> Or worse: the thread is dead, (thread-last-error) returns
> >> nil... but it was cleared from another part of Emacs.
> >
> > This means it exited successfully.  We could also maintain a data
> > structure where successfully-exiting threads will leave their success
> > status together with some id of the message they sent -- unlike a
> > thread that dies abruptly due to an error, a successful thread can
> > store the information in the data structure before exiting.
> 
> Yes why not but then I'd have to modify internals of 'message-send':
> something I thought I could escape.

I thought we were talking about a new function for this purpose, which
would replace message-send, no?  Then that new function could have
this code.





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-07  3:26                                                             ` Eli Zaretskii
@ 2023-11-07  9:06                                                               ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-07 12:12                                                                 ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-07  9:06 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Manuel Giraud <manuel@ledu-giraud.fr>
>> Cc: 63311@debbugs.gnu.org
>> Date: Mon, 06 Nov 2023 21:55:49 +0100
>> 
>> Eli Zaretskii <eliz@gnu.org> writes:
>> 
>> >> If it is dead and (thread-last-error) returns nil maybe we can conclude
>> >> that everything went well.  But if (thread-last-error) returns a
>> >> message, it could be message from any other Emacs thread: what to do in
>> >> such case?
>> >
>> > Display a message about the error.
>> 
>> I mean, the last error message could come from another thread not
>> related in anyway to mail sending.  No?
>
> It could, but why would there be other threads in this case?

It seems that threads aren't used much in Emacs but isn't it dangerous
to consider we're the only one using them?  I don't if it would be easy
but I think that it would be good to have a function like this:

    (thread-error thread)
    
that would return the error message of the given thread like the global
'thread-last-error' does.

>> >> Or worse: the thread is dead, (thread-last-error) returns
>> >> nil... but it was cleared from another part of Emacs.
>> >
>> > This means it exited successfully.  We could also maintain a data
>> > structure where successfully-exiting threads will leave their success
>> > status together with some id of the message they sent -- unlike a
>> > thread that dies abruptly due to an error, a successful thread can
>> > store the information in the data structure before exiting.
>> 
>> Yes why not but then I'd have to modify internals of 'message-send':
>> something I thought I could escape.
>
> I thought we were talking about a new function for this purpose, which
> would replace message-send, no?  Then that new function could have
> this code.

You're right it should be feasible inside this new function with
something like that:

--8<---------------cut here---------------start------------->8---
(make-thread #'(lambda ()
		 (if (message-send)
		     (store-my-success)
		   (store-my-failure))))
--8<---------------cut here---------------end--------------->8---

and then the main-thread will read those success or failure and act
accordingly.
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-07  9:06                                                               ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-07 12:12                                                                 ` Eli Zaretskii
  2023-11-07 12:56                                                                   ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-07 12:12 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Tue, 07 Nov 2023 10:06:58 +0100
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> I mean, the last error message could come from another thread not
> >> related in anyway to mail sending.  No?
> >
> > It could, but why would there be other threads in this case?
> 
> It seems that threads aren't used much in Emacs but isn't it dangerous
> to consider we're the only one using them?  I don't if it would be easy
> but I think that it would be good to have a function like this:
> 
>     (thread-error thread)
>     
> that would return the error message of the given thread like the global
> 'thread-last-error' does.

Maybe.  But we decided not to add this until there's a real need for
it.  Also, threads don't really have a unique ID, at least not easily,
so there's more here than meets the eye...





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-07 12:12                                                                 ` Eli Zaretskii
@ 2023-11-07 12:56                                                                   ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2023-11-07 13:17                                                                     ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-11-07 12:56 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 63311

Eli Zaretskii <eliz@gnu.org> writes:

[...]

>> that would return the error message of the given thread like the global
>> 'thread-last-error' does.
>
> Maybe.  But we decided not to add this until there's a real need for
> it.

Ok.

> Also, threads don't really have a unique ID, at least not easily,
> so there's more here than meets the eye...

What do you mean by this?  Where does this ID come from?
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 41+ messages in thread

* bug#63311: 30.0.50; [PATCH] smtpmail-send-it split
  2023-11-07 12:56                                                                   ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-11-07 13:17                                                                     ` Eli Zaretskii
  0 siblings, 0 replies; 41+ messages in thread
From: Eli Zaretskii @ 2023-11-07 13:17 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 63311

> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Cc: 63311@debbugs.gnu.org
> Date: Tue, 07 Nov 2023 13:56:38 +0100
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > Also, threads don't really have a unique ID, at least not easily,
> > so there's more here than meets the eye...
> 
> What do you mean by this?  Where does this ID come from?

From the underlying threads library, I think.





^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2023-11-07 13:17 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-05-05 13:13 bug#63311: 30.0.50; [PATCH] smtpmail-send-it split Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-05 18:57 ` Eli Zaretskii
     [not found]   ` <874joq34bk.fsf@ledu-giraud.fr>
2023-05-06  6:20     ` Eli Zaretskii
2023-05-06  9:34       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-09  9:52       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-10 11:47         ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-11 13:28           ` Eli Zaretskii
2023-05-11 20:59             ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-12  5:41               ` Eli Zaretskii
2023-05-12  6:24                 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-12  7:09                   ` Eli Zaretskii
2023-05-12  7:57                     ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-01 12:35                       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-01 12:59                         ` Eli Zaretskii
2023-11-01 18:06                           ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-01 19:29                             ` Eli Zaretskii
2023-11-01 19:55                               ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-02  5:48                                 ` Eli Zaretskii
2023-11-02 10:44                                   ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-02 11:26                                     ` Eli Zaretskii
2023-11-05 14:24                                       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-05 15:46                                         ` Eli Zaretskii
2023-11-05 16:12                                           ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-05 16:17                                             ` Eli Zaretskii
2023-11-06 10:21                                               ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-06 12:40                                                 ` Eli Zaretskii
2023-11-06 15:56                                                   ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-06 16:28                                                     ` Eli Zaretskii
2023-11-06 17:57                                                       ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-06 19:21                                                         ` Eli Zaretskii
2023-11-06 20:55                                                           ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-07  3:26                                                             ` Eli Zaretskii
2023-11-07  9:06                                                               ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-07 12:12                                                                 ` Eli Zaretskii
2023-11-07 12:56                                                                   ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-07 13:17                                                                     ` Eli Zaretskii
2023-11-03  2:31                             ` Richard Stallman
2023-11-03  7:18                               ` Eli Zaretskii
2023-11-03 13:49                                 ` Manuel Giraud via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-03 14:29                                   ` Eli Zaretskii
2023-05-12  7:10                   ` Ruijie Yu via Bug reports for GNU Emacs, the Swiss army knife of text editors

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).