branch: externals/ebdb commit 4a422338e3472e6c3de8f6a48e8be7b2c009c048 Author: Eric Abrahamsen <e...@ericabrahamsen.net> Commit: Eric Abrahamsen <e...@ericabrahamsen.net>
Add new ebdb-mail-each command to ebdb-mode * ebdb-com.el (ebdb-mail-each): New command for sending a separate email to multiple records. (ebdb-mode-map): Bind to "M". * ebdb.org: Document. --- ebdb-com.el | 56 ++++++++++++++++++++++++++++- ebdb.info | 115 ++++++++++++++++++++++++++++++++++-------------------------- ebdb.org | 14 ++++++++ ebdb.texi | 13 +++++++ 4 files changed, 147 insertions(+), 51 deletions(-) diff --git a/ebdb-com.el b/ebdb-com.el index 49c282b..76bd59c 100644 --- a/ebdb-com.el +++ b/ebdb-com.el @@ -32,7 +32,8 @@ (eval-and-compile (autoload 'build-mail-aliases "mailalias") (autoload 'browse-url-url-at-point "browse-url") - (autoload 'eieio-customize-object "eieio-custom")) + (autoload 'eieio-customize-object "eieio-custom") + (autoload 'message-goto-body "message")) (require 'crm) (defvar ebdb-crm-local-completion-map @@ -302,6 +303,7 @@ display information." (define-key km (kbd "o") 'ebdb-omit-records) (define-key km (kbd "m") 'ebdb-mail) + (define-key km (kbd "M") 'ebdb-mail-each) (define-key km (kbd "M-d") 'ebdb-dial) (define-key km (kbd "h") 'ebdb-info) (define-key km (kbd "?") 'ebdb-help) @@ -2343,6 +2345,58 @@ for `ebdb-field-action'." (unless (string= "" to) (ebdb-compose-mail to subject))))) +;;;###autoload +(defun ebdb-mail-each (records prompt subject cc bcc body-register) + "Compose a separate email to each of the records in RECORDS. +RECORDS is either the marked records in an *EBDB* buffer, or (if +no records are marked) all the records in the buffer. If PROMPT +is non-nil, prompt the user to choose a mail address to use for +each record that has more than one. SUBJECT is the subject to +use for each message. CC is a list of address strings to put in +the Cc field of each message. BCC likewise, for the Bcc field. +BODY-REGISTER, if given, is a character indicating a register +holding text to be inserted as the body of each message." + (interactive + (list (or (seq-filter (lambda (r) (nth 3 r)) ebdb-records) + (mapcar #'car ebdb-records)) + current-prefix-arg + (ebdb-with-exit (ebdb-read-string "Subject header (C-g to skip): ")) + (ebdb-loop-with-exit + (ebdb-dwim-mail + (ebdb-prompt-for-record + nil nil "Add record to Cc (C-g to skip): "))) + (ebdb-loop-with-exit + (ebdb-dwim-mail + (ebdb-prompt-for-record + nil nil "Add record to Bcc (C-g to skip): "))) + (let ((usable-registers + (seq-filter (lambda (pair) (stringp (cdr pair))) + register-alist))) + (when usable-registers + (ebdb-with-exit + (read-char-choice + "Register to use for body text (C-g to skip): " + (mapcar #'car usable-registers))))))) + (let ((cc (when cc (mapconcat #'identity cc ", "))) + (bcc (when bcc (mapconcat #'identity bcc ", "))) + (body (let ((reg (get-register body-register))) + (when (stringp reg) + reg))) + headers) + (when cc + (push (cons "Cc" cc) headers)) + (when bcc + (push (cons "Bcc" bcc) headers)) + (dolist (rec records) + (funcall #'ebdb-field-mail-compose + rec (ebdb-record-one-mail rec prompt) + subject headers) + (when body + (message-goto-body) + (save-excursion + ;; `register-val-insert' is too new. + (insert-for-yank body)))))) + ;;; Citing (defun ebdb-cite-records-ebdb (arg records style) diff --git a/ebdb.info b/ebdb.info index 3ad612a..10bf542 100644 --- a/ebdb.info +++ b/ebdb.info @@ -1030,6 +1030,17 @@ keybindings apply. Begin composing a message to the record under point (‘ebdb-mail’). With a prefix arg, prompt for the mail address to use; otherwise use the record’s primary address. +‘M’ + Begin composing a separate message to each marked record in the + current {{{buf(EBDB)}} buffer, or all records in the buffer if none + are marked. In addition, prompt for a common subject header line + to use for each message, as well as records to add to the “Cc” and + “Bcc” headers. Then optionally prompt for a character, interpreted + as the name of a register. If that register contains text, insert + the text as the body of each message. + + This function works as a sort of poor-man’s mail merge; it lacks + the ability to interpolate variables in the body text. ‘t’ Toggle between a multi-line and one-line display (see *note @@ -2029,7 +2040,7 @@ Index * ; t: Interactive Commands. (line 42) * ?: The Basics of ebdb-mode. - (line 103) + (line 114) * ^: Searching. (line 55) * Article snarfing: Snarfing. (line 36) * Article snarfing <1>: Article snarfing. (line 6) @@ -2090,14 +2101,14 @@ Index (line 12) * ebdb-cite-records: Citing Records. (line 11) * ebdb-cite-records-ebdb: The Basics of ebdb-mode. - (line 77) + (line 88) * ebdb-clone-buffer: EBDB Buffers. (line 19) * ebdb-copy-fields-as-kill: The Basics of ebdb-mode. - (line 84) + (line 95) * ebdb-copy-mail-as-kill: The Basics of ebdb-mode. - (line 93) + (line 104) * ebdb-copy-records-as-kill: The Basics of ebdb-mode. - (line 89) + (line 100) * ebdb-create-record: Creating Records. (line 6) * ebdb-create-record <1>: The Basics of ebdb-mode. (line 22) @@ -2134,7 +2145,7 @@ Index * ebdb-delete-record-or-field: Deleting Records and Fields. (line 6) * ebdb-display-records-completely: The Basics of ebdb-mode. - (line 66) + (line 77) * ebdb-edit-field: Editing Existing Fields. (line 6) * ebdb-edit-field <1>: The Basics of ebdb-mode. @@ -2156,7 +2167,7 @@ Index * ebdb-hash-extra-predicates: Fast Lookups. (line 30) * ebdb-hashtable: Fast Lookups. (line 10) * ebdb-help: The Basics of ebdb-mode. - (line 103) + (line 114) * ebdb-i18n-countries: Internationalization. (line 44) * ebdb-i18n-countries-pref-scripts: Internationalization. @@ -2164,7 +2175,7 @@ Index * ebdb-ignore-header-list: Auto-Updating Records. (line 44) * ebdb-info: The Basics of ebdb-mode. - (line 106) + (line 117) * ebdb-init-field: Init and Delete Methods. (line 12) * ebdb-insert-field: Inserting New Fields. @@ -2176,6 +2187,8 @@ Index (line 24) * ebdb-mail: The Basics of ebdb-mode. (line 56) +* ebdb-mail-each: The Basics of ebdb-mode. + (line 60) * ebdb-make-buffer-name: Writing Integration For New MUAs. (line 54) * ebdb-message-clean-name-function: Sender name display. (line 14) @@ -2236,7 +2249,7 @@ Index * ebdb-notice-record-hook: Noticing and Automatic Rules. (line 11) * ebdb-omit-records: The Basics of ebdb-mode. - (line 73) + (line 84) * ebdb-org-agenda-popup: Org Integration. (line 32) * ebdb-popup-window: Writing Integration For New MUAs. (line 60) @@ -2248,10 +2261,10 @@ Index (line 50) * ebdb-record-self: Creating Records. (line 21) * ebdb-reformat-records: The Basics of ebdb-mode. - (line 70) + (line 81) * ebdb-rename-buffer: EBDB Buffers. (line 23) * ebdb-save: The Basics of ebdb-mode. - (line 109) + (line 120) * ebdb-save-on-exit: The EBDB Database. (line 78) * ebdb-search-invert: Searching. (line 49) * ebdb-search-pop: Searching. (line 55) @@ -2264,7 +2277,7 @@ Index * ebdb-snarf-routines: Snarfing. (line 26) * ebdb-sources: The EBDB Database. (line 11) * ebdb-toggle-records-format: The Basics of ebdb-mode. - (line 61) + (line 72) * ebdb-try-speedups: The EBDB Database. (line 84) * ebdb-use-diary: Diary Integration. (line 13) * ebdb-user-name-address-re: Auto-Updating Records. @@ -2279,15 +2292,15 @@ Index (line 50) * Field actions <1>: Actions. (line 6) * g: The Basics of ebdb-mode. - (line 100) + (line 111) * h: The Basics of ebdb-mode. - (line 106) + (line 117) * i: Inserting New Fields. (line 6) * i <1>: The Basics of ebdb-mode. (line 30) * I: The Basics of ebdb-mode. - (line 77) + (line 88) * Inserting new fields: Inserting New Fields. (line 6) * Internationalization: Internationalization. @@ -2296,6 +2309,8 @@ Index * Loading databases: The EBDB Database. (line 84) * m: The Basics of ebdb-mode. (line 56) +* M: The Basics of ebdb-mode. + (line 60) * Mail aliases: Mail Aliases. (line 6) * Migration from BBDB: Migration from BBDB. (line 6) * Migration from Org Contacts: Migration from Org Contacts. @@ -2309,39 +2324,39 @@ Index * N: The Basics of ebdb-mode. (line 16) * o: The Basics of ebdb-mode. - (line 73) + (line 84) * p: The Basics of ebdb-mode. (line 13) * P: The Basics of ebdb-mode. (line 19) * q: The Basics of ebdb-mode. - (line 112) + (line 123) * quit-window: The Basics of ebdb-mode. - (line 112) + (line 123) * r: The Basics of ebdb-mode. - (line 70) + (line 81) * read-only of Database: The EBDB Database. (line 20) * record-class of Database: The EBDB Database. (line 37) * RET: The Basics of ebdb-mode. (line 50) * revert-buffer: The Basics of ebdb-mode. - (line 100) + (line 111) * s: The Basics of ebdb-mode. - (line 109) + (line 120) * Saving the database: The EBDB Database. (line 78) * Search history: Searching. (line 51) * Searching the EBDB: Searching. (line 6) * Snarfing text: Snarfing. (line 6) * t: The Basics of ebdb-mode. - (line 61) + (line 72) * T: The Basics of ebdb-mode. - (line 66) + (line 77) * w f: The Basics of ebdb-mode. - (line 84) + (line 95) * w m: The Basics of ebdb-mode. - (line 93) + (line 104) * w r: The Basics of ebdb-mode. - (line 89) + (line 100) @@ -2378,30 +2393,30 @@ Node: EBDB Buffers31129 Node: Searching32342 Node: Changing Search Behavior34004 Node: The Basics of ebdb-mode35251 -Node: Customizing Record Display38944 -Node: Marking43264 -Node: Exporting/Formatting43691 -Node: Completion44640 -Node: Snarfing45838 -Node: Internationalization47855 -Node: Diary Integration50554 -Node: Mail Aliases51419 -Node: vCard Support52133 -Node: Org Integration52632 -Node: Citing Records54530 -Node: Hacking EBDB55288 -Node: Field Classes57607 -Node: Init and Delete Methods60738 -Node: The Labeled Field Class62245 -Node: The Singleton Field Class63099 -Node: Actions63537 -Node: Custom Field Searching64209 -Node: Fast Lookups67076 -Node: Formatting in the EBDB Buffer68886 -Node: Writing Internationalization Libraries70962 -Node: Writing Integration For New MUAs75376 -Node: Article snarfing78823 -Node: Index79541 +Node: Customizing Record Display39566 +Node: Marking43886 +Node: Exporting/Formatting44313 +Node: Completion45262 +Node: Snarfing46460 +Node: Internationalization48477 +Node: Diary Integration51176 +Node: Mail Aliases52041 +Node: vCard Support52755 +Node: Org Integration53254 +Node: Citing Records55152 +Node: Hacking EBDB55910 +Node: Field Classes58229 +Node: Init and Delete Methods61360 +Node: The Labeled Field Class62867 +Node: The Singleton Field Class63721 +Node: Actions64159 +Node: Custom Field Searching64831 +Node: Fast Lookups67698 +Node: Formatting in the EBDB Buffer69508 +Node: Writing Internationalization Libraries71584 +Node: Writing Integration For New MUAs75998 +Node: Article snarfing79445 +Node: Index80163 End Tag Table diff --git a/ebdb.org b/ebdb.org index 481fb90..1f46c20 100644 --- a/ebdb.org +++ b/ebdb.org @@ -917,6 +917,20 @@ keybindings apply. Begin composing a message to the record under point (~ebdb-mail~). With a prefix arg, prompt for the mail address to use; otherwise use the record's primary address. +- M :: + + #+KINDEX: M + #+FINDEX: ebdb-mail-each + Begin composing a separate message to each marked record in the + current {{{buf(EBDB)}} buffer, or all records in the buffer if + none are marked. In addition, prompt for a common subject header + line to use for each message, as well as records to add to the + "Cc" and "Bcc" headers. Then optionally prompt for a character, + interpreted as the name of a register. If that register contains + text, insert the text as the body of each message. + + This function works as a sort of poor-man's mail merge; it lacks + the ability to interpolate variables in the body text. - t :: diff --git a/ebdb.texi b/ebdb.texi index 00f62ad..c5c5369 100644 --- a/ebdb.texi +++ b/ebdb.texi @@ -1124,6 +1124,19 @@ that mail address Begin composing a message to the record under point (@code{ebdb-mail}). With a prefix arg, prompt for the mail address to use; otherwise use the record's primary address. +@item M +@kindex M +@findex ebdb-mail-each +Begin composing a separate message to each marked record in the +current @{@{@{buf(EBDB)@}@} buffer, or all records in the buffer if +none are marked. In addition, prompt for a common subject header +line to use for each message, as well as records to add to the +``Cc'' and ``Bcc'' headers. Then optionally prompt for a character, +interpreted as the name of a register. If that register contains +text, insert the text as the body of each message. + +This function works as a sort of poor-man's mail merge; it lacks +the ability to interpolate variables in the body text. @item t @kindex t