Commit5e97b62eRecorded13 Mar 2026Repositorysigil-jmap
Fix JMAP send compatibility and add batch email move
Message
Drop onSuccessUpdateEmail from EmailSubmission/set (Fastmail rejects the #draft back-reference key) and move email to Sent in a separate Email/set call after successful submission. Add jmap-email-move-many! for batch mailbox moves in a single JMAP request.
Changed
src/sigil/jmap.sgl | 1 +
src/sigil/jmap/email.sgl | 18 ++++++++++++++++++
src/sigil/jmap/send.sgl | 37 +++++++++++++++++++++++--------------
3 files changed, 42 insertions(+), 14 deletions(-)Diff
src/sigil/jmap.sglmodified
@@ -68,6 +68,7 @@
68
jmap-email-get-many 69
jmap-email-update! 70
jmap-email-move!+71
jmap-email-move-many! 72
jmap-email-destroy! 73
jmap-email-set-keyword! 74
jmap-email-remove-keyword!src/sigil/jmap/email.sglmodified
@@ -15,6 +15,7 @@
15
jmap-email-get-many 16
jmap-email-update! 17
jmap-email-move!+18
jmap-email-move-many! 19
jmap-email-destroy! 20
jmap-email-set-keyword! 21
jmap-email-remove-keyword!)@@ -169,6 +170,23 @@
170
(jmap-email-update! client email-id 171
(dict mailboxIds: (dict-set #{} (string->keyword target-mailbox-id) #t)))) 172
+173
;;; Move multiple emails to a mailbox in a single request.+174
;;;+175
;;; ```scheme+176
;;; (jmap-email-move-many! client (list id1 id2 id3) trash-id)+177
;;; ```+178
(define (jmap-email-move-many! client email-ids target-mailbox-id)+179
(: jmap-client? list? string? -> dict?)+180
(let ((updates (fold (lambda (acc id)+181
(dict-set acc (string->keyword id)+182
(dict mailboxIds: #{ target-mailbox-id #t })))+183
#{}+184
email-ids)))+185
(jmap-result-ref client+186
(jmap-call "Email/set"+187
(dict accountId: (jmap-client-account-id client)+188
update: updates)))))+189
190
;;; Delete an email permanently. 191
;;; 192
;;; ```schemesrc/sigil/jmap/send.sglmodified
@@ -116,8 +116,13 @@
116
(error "jmap-send!: to: is required")) 117
118
(let* ((account-id (jmap-client-account-id client))+119
;; Find drafts mailbox to place the email initially+120
(drafts-mailbox (jmap-mailbox-by-role client "drafts"))+121
(drafts-id (if drafts-mailbox (dict-ref drafts-mailbox id: #f) #f)) 122
;; Build the email object−120
(email #{ mailboxIds: #{}+123
(email #{ mailboxIds: (if drafts-id+124
#{ drafts-id #t }+125
#{}) 126
keywords: #{ "$draft" #t } }) 127
(email (if from 128
(dict-set email from: (list->array (list (make-address from))))@@ -163,26 +168,16 @@
168
(email (if (pair? html-parts) 169
(dict-set email htmlBody: (list->array html-parts)) 170
email))−166
;; Find Sent mailbox for onSuccessUpdateEmail−167
(sent-mailbox (jmap-mailbox-by-role client "sent"))−168
(sent-id (if sent-mailbox (dict-ref sent-mailbox id: #f) #f)) 171
;; Build the request: Email/set create + EmailSubmission/set 172
(create-call (jmap-call "Email/set" 173
(dict accountId: account-id 174
create: (dict draft: email)) 175
"c0")) 176
;; Submission with back-reference to created email−175
(submission (dict identityId: identity-id−176
emailId: "#draft"))−177
;; Move to Sent on success−178
(on-success (if sent-id−179
#{ "#draft" #{ mailboxIds: #{ sent-id #t }−180
keywords: 'null } }−181
#{})) 177
(submit-call (jmap-call "EmailSubmission/set" 178
(dict accountId: account-id−184
create: (dict s0: submission)−185
onSuccessUpdateEmail: on-success)+179
create: #{ s0: #{ identityId: identity-id+180
emailId: "#draft" } }) 181
"s0")) 182
(response (jmap-request client create-call submit-call 183
using: %submission-capabilities)))@@ -195,6 +190,20 @@
190
(error "jmap-send!: submission failed" 191
(jmap-error-type response "s0"))) 192
−198
(jmap-response-get response "s0")))))+193
;; Move email from Drafts to Sent+194
(let* ((c0-result (jmap-response-get response "c0"))+195
(created (dict-ref c0-result created: #f))+196
(created-email (and created (dict-ref created draft: #f)))+197
(email-id (and created-email (dict-ref created-email id: #f)))+198
(sent-mailbox (jmap-mailbox-by-role client "sent"))+199
(sent-id (and sent-mailbox (dict-ref sent-mailbox id: #f))))+200
(when (and email-id sent-id)+201
(jmap-request client+202
(jmap-call "Email/set"+203
(dict accountId: account-id+204
update: #{ email-id #{ mailboxIds: #{ sent-id #t }+205
keywords: 'null } }))+206
using: %submission-capabilities))+207
(jmap-response-get response "s0")))))) 208
209
))