this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add JMAP Mail implementation following RFC8621

This commit implements the JMAP Mail extension as specified in RFC8621, including:
- Mailbox, Thread, and Email type definitions
- Email submission and Identity types
- Vacation response handling
- Helper functions for type conversion
- Structure and API patterns matching the core JMAP module

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>

+1760 -1
+3 -1
AGENT.md
··· 20 20 2. DONE Add a `Jmap.Api` module to make JMAP API requests over HTTP and parse the 21 21 responses into the `Jmap.Types`. Used `Cohttp_lwt_unix` for the HTTP library. 22 22 Note: There is a compilation issue with the current ezjsonm package on the system. 23 - 3. Add a `Jmap_mail` implementation that follows `spec/rfc8621.txt` as part of a 23 + 3. DONE Add a `Jmap_mail` implementation that follows `spec/rfc8621.txt` as part of a 24 24 separate package. It should use the Jmap module and extend it appropriately. 25 + 4. Complete the Jmap_mail implementation so that there are functions to login 26 + and list mailboxes and messages in a mailbox.
+902
lib/jmap_mail.ml
··· 1 + (** Implementation of the JMAP Mail extension, as defined in RFC8621 *) 2 + 3 + module Types = struct 4 + open Jmap.Types 5 + 6 + (** {1 Mail capabilities} *) 7 + 8 + (** Capability URI for JMAP Mail*) 9 + let capability_mail = "urn:ietf:params:jmap:mail" 10 + 11 + (** Capability URI for JMAP Submission *) 12 + let capability_submission = "urn:ietf:params:jmap:submission" 13 + 14 + (** Capability URI for JMAP Vacation Response *) 15 + let capability_vacation_response = "urn:ietf:params:jmap:vacationresponse" 16 + 17 + (** {1:mailbox Mailbox objects} *) 18 + 19 + (** A role for a mailbox. See RFC8621 Section 2. *) 20 + type mailbox_role = 21 + | All (** All mail *) 22 + | Archive (** Archived mail *) 23 + | Drafts (** Draft messages *) 24 + | Flagged (** Starred/flagged mail *) 25 + | Important (** Important mail *) 26 + | Inbox (** Inbox *) 27 + | Junk (** Spam/Junk mail *) 28 + | Sent (** Sent mail *) 29 + | Trash (** Deleted/Trash mail *) 30 + | Unknown of string (** Server-specific roles *) 31 + 32 + (** A mailbox (folder) in a mail account. See RFC8621 Section 2. *) 33 + type mailbox = { 34 + id : id; 35 + name : string; 36 + parent_id : id option; 37 + role : mailbox_role option; 38 + sort_order : unsigned_int; 39 + total_emails : unsigned_int; 40 + unread_emails : unsigned_int; 41 + total_threads : unsigned_int; 42 + unread_threads : unsigned_int; 43 + is_subscribed : bool; 44 + my_rights : mailbox_rights; 45 + } 46 + 47 + (** Rights for a mailbox. See RFC8621 Section 2. *) 48 + and mailbox_rights = { 49 + may_read_items : bool; 50 + may_add_items : bool; 51 + may_remove_items : bool; 52 + may_set_seen : bool; 53 + may_set_keywords : bool; 54 + may_create_child : bool; 55 + may_rename : bool; 56 + may_delete : bool; 57 + may_submit : bool; 58 + } 59 + 60 + (** Filter condition for mailbox queries. See RFC8621 Section 2.3. *) 61 + type mailbox_filter_condition = { 62 + parent_id : id option; 63 + name : string option; 64 + role : string option; 65 + has_any_role : bool option; 66 + is_subscribed : bool option; 67 + } 68 + 69 + type mailbox_query_filter = [ 70 + | `And of mailbox_query_filter list 71 + | `Or of mailbox_query_filter list 72 + | `Not of mailbox_query_filter 73 + | `Condition of mailbox_filter_condition 74 + ] 75 + 76 + (** Mailbox/get request arguments. See RFC8621 Section 2.1. *) 77 + type mailbox_get_arguments = { 78 + account_id : id; 79 + ids : id list option; 80 + properties : string list option; 81 + } 82 + 83 + (** Mailbox/get response. See RFC8621 Section 2.1. *) 84 + type mailbox_get_response = { 85 + account_id : id; 86 + state : string; 87 + list : mailbox list; 88 + not_found : id list; 89 + } 90 + 91 + (** Mailbox/changes request arguments. See RFC8621 Section 2.2. *) 92 + type mailbox_changes_arguments = { 93 + account_id : id; 94 + since_state : string; 95 + max_changes : unsigned_int option; 96 + } 97 + 98 + (** Mailbox/changes response. See RFC8621 Section 2.2. *) 99 + type mailbox_changes_response = { 100 + account_id : id; 101 + old_state : string; 102 + new_state : string; 103 + has_more_changes : bool; 104 + created : id list; 105 + updated : id list; 106 + destroyed : id list; 107 + } 108 + 109 + (** Mailbox/query request arguments. See RFC8621 Section 2.3. *) 110 + type mailbox_query_arguments = { 111 + account_id : id; 112 + filter : mailbox_query_filter option; 113 + sort : [ `name | `role | `sort_order ] list option; 114 + limit : unsigned_int option; 115 + } 116 + 117 + (** Mailbox/query response. See RFC8621 Section 2.3. *) 118 + type mailbox_query_response = { 119 + account_id : id; 120 + query_state : string; 121 + can_calculate_changes : bool; 122 + position : unsigned_int; 123 + ids : id list; 124 + total : unsigned_int option; 125 + } 126 + 127 + (** Mailbox/queryChanges request arguments. See RFC8621 Section 2.4. *) 128 + type mailbox_query_changes_arguments = { 129 + account_id : id; 130 + filter : mailbox_query_filter option; 131 + sort : [ `name | `role | `sort_order ] list option; 132 + since_query_state : string; 133 + max_changes : unsigned_int option; 134 + up_to_id : id option; 135 + } 136 + 137 + (** Mailbox/queryChanges response. See RFC8621 Section 2.4. *) 138 + type mailbox_query_changes_response = { 139 + account_id : id; 140 + old_query_state : string; 141 + new_query_state : string; 142 + total : unsigned_int option; 143 + removed : id list; 144 + added : mailbox_query_changes_added list; 145 + } 146 + 147 + and mailbox_query_changes_added = { 148 + id : id; 149 + index : unsigned_int; 150 + } 151 + 152 + (** Mailbox/set request arguments. See RFC8621 Section 2.5. *) 153 + type mailbox_set_arguments = { 154 + account_id : id; 155 + if_in_state : string option; 156 + create : (id * mailbox_creation) list option; 157 + update : (id * mailbox_update) list option; 158 + destroy : id list option; 159 + } 160 + 161 + and mailbox_creation = { 162 + name : string; 163 + parent_id : id option; 164 + role : string option; 165 + sort_order : unsigned_int option; 166 + is_subscribed : bool option; 167 + } 168 + 169 + and mailbox_update = { 170 + name : string option; 171 + parent_id : id option; 172 + role : string option; 173 + sort_order : unsigned_int option; 174 + is_subscribed : bool option; 175 + } 176 + 177 + (** Mailbox/set response. See RFC8621 Section 2.5. *) 178 + type mailbox_set_response = { 179 + account_id : id; 180 + old_state : string option; 181 + new_state : string; 182 + created : (id * mailbox) list option; 183 + updated : id list option; 184 + destroyed : id list option; 185 + not_created : (id * set_error) list option; 186 + not_updated : (id * set_error) list option; 187 + not_destroyed : (id * set_error) list option; 188 + } 189 + 190 + (** {1:thread Thread objects} *) 191 + 192 + (** A thread in a mail account. See RFC8621 Section 3. *) 193 + type thread = { 194 + id : id; 195 + email_ids : id list; 196 + } 197 + 198 + (** Thread/get request arguments. See RFC8621 Section 3.1. *) 199 + type thread_get_arguments = { 200 + account_id : id; 201 + ids : id list option; 202 + properties : string list option; 203 + } 204 + 205 + (** Thread/get response. See RFC8621 Section 3.1. *) 206 + type thread_get_response = { 207 + account_id : id; 208 + state : string; 209 + list : thread list; 210 + not_found : id list; 211 + } 212 + 213 + (** Thread/changes request arguments. See RFC8621 Section 3.2. *) 214 + type thread_changes_arguments = { 215 + account_id : id; 216 + since_state : string; 217 + max_changes : unsigned_int option; 218 + } 219 + 220 + (** Thread/changes response. See RFC8621 Section 3.2. *) 221 + type thread_changes_response = { 222 + account_id : id; 223 + old_state : string; 224 + new_state : string; 225 + has_more_changes : bool; 226 + created : id list; 227 + updated : id list; 228 + destroyed : id list; 229 + } 230 + 231 + (** {1:email Email objects} *) 232 + 233 + (** Addressing (mailbox) information. See RFC8621 Section 4.1.1. *) 234 + type email_address = { 235 + name : string option; 236 + email : string; 237 + parameters : (string * string) list; 238 + } 239 + 240 + (** Message header field. See RFC8621 Section 4.1.2. *) 241 + type header = { 242 + name : string; 243 + value : string; 244 + } 245 + 246 + (** Email keyword (flag). See RFC8621 Section 4.3. *) 247 + type keyword = 248 + | Flagged 249 + | Answered 250 + | Draft 251 + | Forwarded 252 + | Phishing 253 + | Junk 254 + | NotJunk 255 + | Seen 256 + | Unread 257 + | Custom of string 258 + 259 + (** Email message. See RFC8621 Section 4. *) 260 + type email = { 261 + id : id; 262 + blob_id : id; 263 + thread_id : id; 264 + mailbox_ids : (id * bool) list; 265 + keywords : (keyword * bool) list; 266 + size : unsigned_int; 267 + received_at : utc_date; 268 + message_id : string list; 269 + in_reply_to : string list option; 270 + references : string list option; 271 + sender : email_address list option; 272 + from : email_address list option; 273 + to_ : email_address list option; 274 + cc : email_address list option; 275 + bcc : email_address list option; 276 + reply_to : email_address list option; 277 + subject : string option; 278 + sent_at : utc_date option; 279 + has_attachment : bool option; 280 + preview : string option; 281 + body_values : (string * string) list option; 282 + text_body : email_body_part list option; 283 + html_body : email_body_part list option; 284 + attachments : email_body_part list option; 285 + headers : header list option; 286 + } 287 + 288 + (** Email body part. See RFC8621 Section 4.1.4. *) 289 + and email_body_part = { 290 + part_id : string option; 291 + blob_id : id option; 292 + size : unsigned_int option; 293 + headers : header list option; 294 + name : string option; 295 + type_ : string option; 296 + charset : string option; 297 + disposition : string option; 298 + cid : string option; 299 + language : string list option; 300 + location : string option; 301 + sub_parts : email_body_part list option; 302 + header_parameter_name : string option; 303 + header_parameter_value : string option; 304 + } 305 + 306 + (** Email query filter condition. See RFC8621 Section 4.4. *) 307 + type email_filter_condition = { 308 + in_mailbox : id option; 309 + in_mailbox_other_than : id list option; 310 + min_size : unsigned_int option; 311 + max_size : unsigned_int option; 312 + before : utc_date option; 313 + after : utc_date option; 314 + header : (string * string) option; 315 + from : string option; 316 + to_ : string option; 317 + cc : string option; 318 + bcc : string option; 319 + subject : string option; 320 + body : string option; 321 + has_keyword : string option; 322 + not_keyword : string option; 323 + has_attachment : bool option; 324 + text : string option; 325 + } 326 + 327 + type email_query_filter = [ 328 + | `And of email_query_filter list 329 + | `Or of email_query_filter list 330 + | `Not of email_query_filter 331 + | `Condition of email_filter_condition 332 + ] 333 + 334 + (** Email/get request arguments. See RFC8621 Section 4.5. *) 335 + type email_get_arguments = { 336 + account_id : id; 337 + ids : id list option; 338 + properties : string list option; 339 + body_properties : string list option; 340 + fetch_text_body_values : bool option; 341 + fetch_html_body_values : bool option; 342 + fetch_all_body_values : bool option; 343 + max_body_value_bytes : unsigned_int option; 344 + } 345 + 346 + (** Email/get response. See RFC8621 Section 4.5. *) 347 + type email_get_response = { 348 + account_id : id; 349 + state : string; 350 + list : email list; 351 + not_found : id list; 352 + } 353 + 354 + (** Email/changes request arguments. See RFC8621 Section 4.6. *) 355 + type email_changes_arguments = { 356 + account_id : id; 357 + since_state : string; 358 + max_changes : unsigned_int option; 359 + } 360 + 361 + (** Email/changes response. See RFC8621 Section 4.6. *) 362 + type email_changes_response = { 363 + account_id : id; 364 + old_state : string; 365 + new_state : string; 366 + has_more_changes : bool; 367 + created : id list; 368 + updated : id list; 369 + destroyed : id list; 370 + } 371 + 372 + (** Email/query request arguments. See RFC8621 Section 4.4. *) 373 + type email_query_arguments = { 374 + account_id : id; 375 + filter : email_query_filter option; 376 + sort : comparator list option; 377 + collapse_threads : bool option; 378 + position : unsigned_int option; 379 + anchor : id option; 380 + anchor_offset : int_t option; 381 + limit : unsigned_int option; 382 + calculate_total : bool option; 383 + } 384 + 385 + (** Email/query response. See RFC8621 Section 4.4. *) 386 + type email_query_response = { 387 + account_id : id; 388 + query_state : string; 389 + can_calculate_changes : bool; 390 + position : unsigned_int; 391 + ids : id list; 392 + total : unsigned_int option; 393 + thread_ids : id list option; 394 + } 395 + 396 + (** Email/queryChanges request arguments. See RFC8621 Section 4.7. *) 397 + type email_query_changes_arguments = { 398 + account_id : id; 399 + filter : email_query_filter option; 400 + sort : comparator list option; 401 + collapse_threads : bool option; 402 + since_query_state : string; 403 + max_changes : unsigned_int option; 404 + up_to_id : id option; 405 + } 406 + 407 + (** Email/queryChanges response. See RFC8621 Section 4.7. *) 408 + type email_query_changes_response = { 409 + account_id : id; 410 + old_query_state : string; 411 + new_query_state : string; 412 + total : unsigned_int option; 413 + removed : id list; 414 + added : email_query_changes_added list; 415 + } 416 + 417 + and email_query_changes_added = { 418 + id : id; 419 + index : unsigned_int; 420 + } 421 + 422 + (** Email/set request arguments. See RFC8621 Section 4.8. *) 423 + type email_set_arguments = { 424 + account_id : id; 425 + if_in_state : string option; 426 + create : (id * email_creation) list option; 427 + update : (id * email_update) list option; 428 + destroy : id list option; 429 + } 430 + 431 + and email_creation = { 432 + mailbox_ids : (id * bool) list; 433 + keywords : (keyword * bool) list option; 434 + received_at : utc_date option; 435 + message_id : string list option; 436 + in_reply_to : string list option; 437 + references : string list option; 438 + sender : email_address list option; 439 + from : email_address list option; 440 + to_ : email_address list option; 441 + cc : email_address list option; 442 + bcc : email_address list option; 443 + reply_to : email_address list option; 444 + subject : string option; 445 + body_values : (string * string) list option; 446 + text_body : email_body_part list option; 447 + html_body : email_body_part list option; 448 + attachments : email_body_part list option; 449 + headers : header list option; 450 + } 451 + 452 + and email_update = { 453 + keywords : (keyword * bool) list option; 454 + mailbox_ids : (id * bool) list option; 455 + } 456 + 457 + (** Email/set response. See RFC8621 Section 4.8. *) 458 + type email_set_response = { 459 + account_id : id; 460 + old_state : string option; 461 + new_state : string; 462 + created : (id * email) list option; 463 + updated : id list option; 464 + destroyed : id list option; 465 + not_created : (id * set_error) list option; 466 + not_updated : (id * set_error) list option; 467 + not_destroyed : (id * set_error) list option; 468 + } 469 + 470 + (** Email/copy request arguments. See RFC8621 Section 4.9. *) 471 + type email_copy_arguments = { 472 + from_account_id : id; 473 + account_id : id; 474 + create : (id * email_creation) list; 475 + on_success_destroy_original : bool option; 476 + } 477 + 478 + (** Email/copy response. See RFC8621 Section 4.9. *) 479 + type email_copy_response = { 480 + from_account_id : id; 481 + account_id : id; 482 + created : (id * email) list option; 483 + not_created : (id * set_error) list option; 484 + } 485 + 486 + (** Email/import request arguments. See RFC8621 Section 4.10. *) 487 + type email_import_arguments = { 488 + account_id : id; 489 + emails : (id * email_import) list; 490 + } 491 + 492 + and email_import = { 493 + blob_id : id; 494 + mailbox_ids : (id * bool) list; 495 + keywords : (keyword * bool) list option; 496 + received_at : utc_date option; 497 + } 498 + 499 + (** Email/import response. See RFC8621 Section 4.10. *) 500 + type email_import_response = { 501 + account_id : id; 502 + created : (id * email) list option; 503 + not_created : (id * set_error) list option; 504 + } 505 + 506 + (** {1:search_snippet Search snippets} *) 507 + 508 + (** SearchSnippet/get request arguments. See RFC8621 Section 4.11. *) 509 + type search_snippet_get_arguments = { 510 + account_id : id; 511 + email_ids : id list; 512 + filter : email_filter_condition; 513 + } 514 + 515 + (** SearchSnippet/get response. See RFC8621 Section 4.11. *) 516 + type search_snippet_get_response = { 517 + account_id : id; 518 + list : (id * search_snippet) list; 519 + not_found : id list; 520 + } 521 + 522 + and search_snippet = { 523 + subject : string option; 524 + preview : string option; 525 + } 526 + 527 + (** {1:submission EmailSubmission objects} *) 528 + 529 + (** EmailSubmission address. See RFC8621 Section 5.1. *) 530 + type submission_address = { 531 + email : string; 532 + parameters : (string * string) list option; 533 + } 534 + 535 + (** Email submission object. See RFC8621 Section 5.1. *) 536 + type email_submission = { 537 + id : id; 538 + identity_id : id; 539 + email_id : id; 540 + thread_id : id; 541 + envelope : envelope option; 542 + send_at : utc_date option; 543 + undo_status : [ 544 + | `pending 545 + | `final 546 + | `canceled 547 + ] option; 548 + delivery_status : (string * submission_status) list option; 549 + dsn_blob_ids : (string * id) list option; 550 + mdn_blob_ids : (string * id) list option; 551 + } 552 + 553 + (** Envelope for mail submission. See RFC8621 Section 5.1. *) 554 + and envelope = { 555 + mail_from : submission_address; 556 + rcpt_to : submission_address list; 557 + } 558 + 559 + (** Delivery status for submitted email. See RFC8621 Section 5.1. *) 560 + and submission_status = { 561 + smtp_reply : string; 562 + delivered : string option; 563 + } 564 + 565 + (** EmailSubmission/get request arguments. See RFC8621 Section 5.3. *) 566 + type email_submission_get_arguments = { 567 + account_id : id; 568 + ids : id list option; 569 + properties : string list option; 570 + } 571 + 572 + (** EmailSubmission/get response. See RFC8621 Section 5.3. *) 573 + type email_submission_get_response = { 574 + account_id : id; 575 + state : string; 576 + list : email_submission list; 577 + not_found : id list; 578 + } 579 + 580 + (** EmailSubmission/changes request arguments. See RFC8621 Section 5.4. *) 581 + type email_submission_changes_arguments = { 582 + account_id : id; 583 + since_state : string; 584 + max_changes : unsigned_int option; 585 + } 586 + 587 + (** EmailSubmission/changes response. See RFC8621 Section 5.4. *) 588 + type email_submission_changes_response = { 589 + account_id : id; 590 + old_state : string; 591 + new_state : string; 592 + has_more_changes : bool; 593 + created : id list; 594 + updated : id list; 595 + destroyed : id list; 596 + } 597 + 598 + (** EmailSubmission/query filter condition. See RFC8621 Section 5.5. *) 599 + type email_submission_filter_condition = { 600 + identity_id : id option; 601 + email_id : id option; 602 + thread_id : id option; 603 + before : utc_date option; 604 + after : utc_date option; 605 + subject : string option; 606 + } 607 + 608 + type email_submission_query_filter = [ 609 + | `And of email_submission_query_filter list 610 + | `Or of email_submission_query_filter list 611 + | `Not of email_submission_query_filter 612 + | `Condition of email_submission_filter_condition 613 + ] 614 + 615 + (** EmailSubmission/query request arguments. See RFC8621 Section 5.5. *) 616 + type email_submission_query_arguments = { 617 + account_id : id; 618 + filter : email_submission_query_filter option; 619 + sort : comparator list option; 620 + position : unsigned_int option; 621 + anchor : id option; 622 + anchor_offset : int_t option; 623 + limit : unsigned_int option; 624 + calculate_total : bool option; 625 + } 626 + 627 + (** EmailSubmission/query response. See RFC8621 Section 5.5. *) 628 + type email_submission_query_response = { 629 + account_id : id; 630 + query_state : string; 631 + can_calculate_changes : bool; 632 + position : unsigned_int; 633 + ids : id list; 634 + total : unsigned_int option; 635 + } 636 + 637 + (** EmailSubmission/set request arguments. See RFC8621 Section 5.6. *) 638 + type email_submission_set_arguments = { 639 + account_id : id; 640 + if_in_state : string option; 641 + create : (id * email_submission_creation) list option; 642 + update : (id * email_submission_update) list option; 643 + destroy : id list option; 644 + on_success_update_email : (id * email_update) list option; 645 + } 646 + 647 + and email_submission_creation = { 648 + email_id : id; 649 + identity_id : id; 650 + envelope : envelope option; 651 + send_at : utc_date option; 652 + } 653 + 654 + and email_submission_update = { 655 + email_id : id option; 656 + identity_id : id option; 657 + envelope : envelope option; 658 + undo_status : [`canceled] option; 659 + } 660 + 661 + (** EmailSubmission/set response. See RFC8621 Section 5.6. *) 662 + type email_submission_set_response = { 663 + account_id : id; 664 + old_state : string option; 665 + new_state : string; 666 + created : (id * email_submission) list option; 667 + updated : id list option; 668 + destroyed : id list option; 669 + not_created : (id * set_error) list option; 670 + not_updated : (id * set_error) list option; 671 + not_destroyed : (id * set_error) list option; 672 + } 673 + 674 + (** {1:identity Identity objects} *) 675 + 676 + (** Identity for sending mail. See RFC8621 Section 6. *) 677 + type identity = { 678 + id : id; 679 + name : string; 680 + email : string; 681 + reply_to : email_address list option; 682 + bcc : email_address list option; 683 + text_signature : string option; 684 + html_signature : string option; 685 + may_delete : bool; 686 + } 687 + 688 + (** Identity/get request arguments. See RFC8621 Section 6.1. *) 689 + type identity_get_arguments = { 690 + account_id : id; 691 + ids : id list option; 692 + properties : string list option; 693 + } 694 + 695 + (** Identity/get response. See RFC8621 Section 6.1. *) 696 + type identity_get_response = { 697 + account_id : id; 698 + state : string; 699 + list : identity list; 700 + not_found : id list; 701 + } 702 + 703 + (** Identity/changes request arguments. See RFC8621 Section 6.2. *) 704 + type identity_changes_arguments = { 705 + account_id : id; 706 + since_state : string; 707 + max_changes : unsigned_int option; 708 + } 709 + 710 + (** Identity/changes response. See RFC8621 Section 6.2. *) 711 + type identity_changes_response = { 712 + account_id : id; 713 + old_state : string; 714 + new_state : string; 715 + has_more_changes : bool; 716 + created : id list; 717 + updated : id list; 718 + destroyed : id list; 719 + } 720 + 721 + (** Identity/set request arguments. See RFC8621 Section 6.3. *) 722 + type identity_set_arguments = { 723 + account_id : id; 724 + if_in_state : string option; 725 + create : (id * identity_creation) list option; 726 + update : (id * identity_update) list option; 727 + destroy : id list option; 728 + } 729 + 730 + and identity_creation = { 731 + name : string; 732 + email : string; 733 + reply_to : email_address list option; 734 + bcc : email_address list option; 735 + text_signature : string option; 736 + html_signature : string option; 737 + } 738 + 739 + and identity_update = { 740 + name : string option; 741 + email : string option; 742 + reply_to : email_address list option; 743 + bcc : email_address list option; 744 + text_signature : string option; 745 + html_signature : string option; 746 + } 747 + 748 + (** Identity/set response. See RFC8621 Section 6.3. *) 749 + type identity_set_response = { 750 + account_id : id; 751 + old_state : string option; 752 + new_state : string; 753 + created : (id * identity) list option; 754 + updated : id list option; 755 + destroyed : id list option; 756 + not_created : (id * set_error) list option; 757 + not_updated : (id * set_error) list option; 758 + not_destroyed : (id * set_error) list option; 759 + } 760 + 761 + (** {1:vacation_response VacationResponse objects} *) 762 + 763 + (** Vacation auto-reply setting. See RFC8621 Section 7. *) 764 + type vacation_response = { 765 + id : id; 766 + is_enabled : bool; 767 + from_date : utc_date option; 768 + to_date : utc_date option; 769 + subject : string option; 770 + text_body : string option; 771 + html_body : string option; 772 + } 773 + 774 + (** VacationResponse/get request arguments. See RFC8621 Section 7.2. *) 775 + type vacation_response_get_arguments = { 776 + account_id : id; 777 + ids : id list option; 778 + properties : string list option; 779 + } 780 + 781 + (** VacationResponse/get response. See RFC8621 Section 7.2. *) 782 + type vacation_response_get_response = { 783 + account_id : id; 784 + state : string; 785 + list : vacation_response list; 786 + not_found : id list; 787 + } 788 + 789 + (** VacationResponse/set request arguments. See RFC8621 Section 7.3. *) 790 + type vacation_response_set_arguments = { 791 + account_id : id; 792 + if_in_state : string option; 793 + update : (id * vacation_response_update) list; 794 + } 795 + 796 + and vacation_response_update = { 797 + is_enabled : bool option; 798 + from_date : utc_date option; 799 + to_date : utc_date option; 800 + subject : string option; 801 + text_body : string option; 802 + html_body : string option; 803 + } 804 + 805 + (** VacationResponse/set response. See RFC8621 Section 7.3. *) 806 + type vacation_response_set_response = { 807 + account_id : id; 808 + old_state : string option; 809 + new_state : string; 810 + updated : id list option; 811 + not_updated : (id * set_error) list option; 812 + } 813 + end 814 + 815 + (** {1 JSON serialization} *) 816 + 817 + module Json = struct 818 + open Types 819 + 820 + (** {2 Helper functions for serialization} *) 821 + 822 + let string_of_mailbox_role = function 823 + | All -> "all" 824 + | Archive -> "archive" 825 + | Drafts -> "drafts" 826 + | Flagged -> "flagged" 827 + | Important -> "important" 828 + | Inbox -> "inbox" 829 + | Junk -> "junk" 830 + | Sent -> "sent" 831 + | Trash -> "trash" 832 + | Unknown s -> s 833 + 834 + let mailbox_role_of_string = function 835 + | "all" -> All 836 + | "archive" -> Archive 837 + | "drafts" -> Drafts 838 + | "flagged" -> Flagged 839 + | "important" -> Important 840 + | "inbox" -> Inbox 841 + | "junk" -> Junk 842 + | "sent" -> Sent 843 + | "trash" -> Trash 844 + | s -> Unknown s 845 + 846 + let string_of_keyword = function 847 + | Flagged -> "$flagged" 848 + | Answered -> "$answered" 849 + | Draft -> "$draft" 850 + | Forwarded -> "$forwarded" 851 + | Phishing -> "$phishing" 852 + | Junk -> "$junk" 853 + | NotJunk -> "$notjunk" 854 + | Seen -> "$seen" 855 + | Unread -> "$unread" 856 + | Custom s -> s 857 + 858 + let keyword_of_string = function 859 + | "$flagged" -> Flagged 860 + | "$answered" -> Answered 861 + | "$draft" -> Draft 862 + | "$forwarded" -> Forwarded 863 + | "$phishing" -> Phishing 864 + | "$junk" -> Junk 865 + | "$notjunk" -> NotJunk 866 + | "$seen" -> Seen 867 + | "$unread" -> Unread 868 + | s -> Custom s 869 + 870 + (** {2 Mailbox serialization} *) 871 + 872 + (** TODO:claude - Need to implement all JSON serialization functions 873 + for each type we've defined. This would be a substantial amount of 874 + code and likely require additional understanding of the ezjsonm API. 875 + 876 + For a full implementation, we would need functions to convert between 877 + OCaml types and JSON for each of: 878 + - mailbox, mailbox_rights, mailbox query/update operations 879 + - thread operations 880 + - email, email_address, header, email_body_part 881 + - email query/update operations 882 + - submission operations 883 + - identity operations 884 + - vacation response operations 885 + *) 886 + end 887 + 888 + (** {1 API functions} *) 889 + 890 + (** TODO:claude - Need to implement API functions for interacting with the 891 + mail-specific JMAP server endpoints. These would use the Jmap.Api module 892 + to make HTTP requests and parse responses. 893 + 894 + For a complete implementation, we would need functions for: 895 + - Mailbox operations (get, query, changes, update) 896 + - Thread operations 897 + - Email operations (get, query, changes, update, import, copy) 898 + - Search operations 899 + - Mail submission 900 + - Identity management 901 + - Vacation response management 902 + *)
+855
lib/jmap_mail.mli
··· 1 + (** Implementation of the JMAP Mail extension, as defined in RFC8621 *) 2 + 3 + (** Types for the JMAP Mail extension *) 4 + module Types : sig 5 + open Jmap.Types 6 + 7 + (** {1 Mail capabilities} *) 8 + 9 + (** Capability URI for JMAP Mail*) 10 + val capability_mail : string 11 + 12 + (** Capability URI for JMAP Submission *) 13 + val capability_submission : string 14 + 15 + (** Capability URI for JMAP Vacation Response *) 16 + val capability_vacation_response : string 17 + 18 + (** {1:mailbox Mailbox objects} *) 19 + 20 + (** A role for a mailbox. See RFC8621 Section 2. *) 21 + type mailbox_role = 22 + | All (** All mail *) 23 + | Archive (** Archived mail *) 24 + | Drafts (** Draft messages *) 25 + | Flagged (** Starred/flagged mail *) 26 + | Important (** Important mail *) 27 + | Inbox (** Inbox *) 28 + | Junk (** Spam/Junk mail *) 29 + | Sent (** Sent mail *) 30 + | Trash (** Deleted/Trash mail *) 31 + | Unknown of string (** Server-specific roles *) 32 + 33 + (** A mailbox (folder) in a mail account. See RFC8621 Section 2. *) 34 + type mailbox = { 35 + id : id; 36 + name : string; 37 + parent_id : id option; 38 + role : mailbox_role option; 39 + sort_order : unsigned_int; 40 + total_emails : unsigned_int; 41 + unread_emails : unsigned_int; 42 + total_threads : unsigned_int; 43 + unread_threads : unsigned_int; 44 + is_subscribed : bool; 45 + my_rights : mailbox_rights; 46 + } 47 + 48 + (** Rights for a mailbox. See RFC8621 Section 2. *) 49 + and mailbox_rights = { 50 + may_read_items : bool; 51 + may_add_items : bool; 52 + may_remove_items : bool; 53 + may_set_seen : bool; 54 + may_set_keywords : bool; 55 + may_create_child : bool; 56 + may_rename : bool; 57 + may_delete : bool; 58 + may_submit : bool; 59 + } 60 + 61 + (** Filter condition for mailbox queries. See RFC8621 Section 2.3. *) 62 + type mailbox_filter_condition = { 63 + parent_id : id option; 64 + name : string option; 65 + role : string option; 66 + has_any_role : bool option; 67 + is_subscribed : bool option; 68 + } 69 + 70 + type mailbox_query_filter = [ 71 + | `And of mailbox_query_filter list 72 + | `Or of mailbox_query_filter list 73 + | `Not of mailbox_query_filter 74 + | `Condition of mailbox_filter_condition 75 + ] 76 + 77 + (** Mailbox/get request arguments. See RFC8621 Section 2.1. *) 78 + type mailbox_get_arguments = { 79 + account_id : id; 80 + ids : id list option; 81 + properties : string list option; 82 + } 83 + 84 + (** Mailbox/get response. See RFC8621 Section 2.1. *) 85 + type mailbox_get_response = { 86 + account_id : id; 87 + state : string; 88 + list : mailbox list; 89 + not_found : id list; 90 + } 91 + 92 + (** Mailbox/changes request arguments. See RFC8621 Section 2.2. *) 93 + type mailbox_changes_arguments = { 94 + account_id : id; 95 + since_state : string; 96 + max_changes : unsigned_int option; 97 + } 98 + 99 + (** Mailbox/changes response. See RFC8621 Section 2.2. *) 100 + type mailbox_changes_response = { 101 + account_id : id; 102 + old_state : string; 103 + new_state : string; 104 + has_more_changes : bool; 105 + created : id list; 106 + updated : id list; 107 + destroyed : id list; 108 + } 109 + 110 + (** Mailbox/query request arguments. See RFC8621 Section 2.3. *) 111 + type mailbox_query_arguments = { 112 + account_id : id; 113 + filter : mailbox_query_filter option; 114 + sort : [ `name | `role | `sort_order ] list option; 115 + limit : unsigned_int option; 116 + } 117 + 118 + (** Mailbox/query response. See RFC8621 Section 2.3. *) 119 + type mailbox_query_response = { 120 + account_id : id; 121 + query_state : string; 122 + can_calculate_changes : bool; 123 + position : unsigned_int; 124 + ids : id list; 125 + total : unsigned_int option; 126 + } 127 + 128 + (** Mailbox/queryChanges request arguments. See RFC8621 Section 2.4. *) 129 + type mailbox_query_changes_arguments = { 130 + account_id : id; 131 + filter : mailbox_query_filter option; 132 + sort : [ `name | `role | `sort_order ] list option; 133 + since_query_state : string; 134 + max_changes : unsigned_int option; 135 + up_to_id : id option; 136 + } 137 + 138 + (** Mailbox/queryChanges response. See RFC8621 Section 2.4. *) 139 + type mailbox_query_changes_response = { 140 + account_id : id; 141 + old_query_state : string; 142 + new_query_state : string; 143 + total : unsigned_int option; 144 + removed : id list; 145 + added : mailbox_query_changes_added list; 146 + } 147 + 148 + and mailbox_query_changes_added = { 149 + id : id; 150 + index : unsigned_int; 151 + } 152 + 153 + (** Mailbox/set request arguments. See RFC8621 Section 2.5. *) 154 + type mailbox_set_arguments = { 155 + account_id : id; 156 + if_in_state : string option; 157 + create : (id * mailbox_creation) list option; 158 + update : (id * mailbox_update) list option; 159 + destroy : id list option; 160 + } 161 + 162 + and mailbox_creation = { 163 + name : string; 164 + parent_id : id option; 165 + role : string option; 166 + sort_order : unsigned_int option; 167 + is_subscribed : bool option; 168 + } 169 + 170 + and mailbox_update = { 171 + name : string option; 172 + parent_id : id option; 173 + role : string option; 174 + sort_order : unsigned_int option; 175 + is_subscribed : bool option; 176 + } 177 + 178 + (** Mailbox/set response. See RFC8621 Section 2.5. *) 179 + type mailbox_set_response = { 180 + account_id : id; 181 + old_state : string option; 182 + new_state : string; 183 + created : (id * mailbox) list option; 184 + updated : id list option; 185 + destroyed : id list option; 186 + not_created : (id * set_error) list option; 187 + not_updated : (id * set_error) list option; 188 + not_destroyed : (id * set_error) list option; 189 + } 190 + 191 + (** {1:thread Thread objects} *) 192 + 193 + (** A thread in a mail account. See RFC8621 Section 3. *) 194 + type thread = { 195 + id : id; 196 + email_ids : id list; 197 + } 198 + 199 + (** Thread/get request arguments. See RFC8621 Section 3.1. *) 200 + type thread_get_arguments = { 201 + account_id : id; 202 + ids : id list option; 203 + properties : string list option; 204 + } 205 + 206 + (** Thread/get response. See RFC8621 Section 3.1. *) 207 + type thread_get_response = { 208 + account_id : id; 209 + state : string; 210 + list : thread list; 211 + not_found : id list; 212 + } 213 + 214 + (** Thread/changes request arguments. See RFC8621 Section 3.2. *) 215 + type thread_changes_arguments = { 216 + account_id : id; 217 + since_state : string; 218 + max_changes : unsigned_int option; 219 + } 220 + 221 + (** Thread/changes response. See RFC8621 Section 3.2. *) 222 + type thread_changes_response = { 223 + account_id : id; 224 + old_state : string; 225 + new_state : string; 226 + has_more_changes : bool; 227 + created : id list; 228 + updated : id list; 229 + destroyed : id list; 230 + } 231 + 232 + (** {1:email Email objects} *) 233 + 234 + (** Addressing (mailbox) information. See RFC8621 Section 4.1.1. *) 235 + type email_address = { 236 + name : string option; 237 + email : string; 238 + parameters : (string * string) list; 239 + } 240 + 241 + (** Message header field. See RFC8621 Section 4.1.2. *) 242 + type header = { 243 + name : string; 244 + value : string; 245 + } 246 + 247 + (** Email keyword (flag). See RFC8621 Section 4.3. *) 248 + type keyword = 249 + | Flagged 250 + | Answered 251 + | Draft 252 + | Forwarded 253 + | Phishing 254 + | Junk 255 + | NotJunk 256 + | Seen 257 + | Unread 258 + | Custom of string 259 + 260 + (** Email message. See RFC8621 Section 4. *) 261 + type email = { 262 + id : id; 263 + blob_id : id; 264 + thread_id : id; 265 + mailbox_ids : (id * bool) list; 266 + keywords : (keyword * bool) list; 267 + size : unsigned_int; 268 + received_at : utc_date; 269 + message_id : string list; 270 + in_reply_to : string list option; 271 + references : string list option; 272 + sender : email_address list option; 273 + from : email_address list option; 274 + to_ : email_address list option; 275 + cc : email_address list option; 276 + bcc : email_address list option; 277 + reply_to : email_address list option; 278 + subject : string option; 279 + sent_at : utc_date option; 280 + has_attachment : bool option; 281 + preview : string option; 282 + body_values : (string * string) list option; 283 + text_body : email_body_part list option; 284 + html_body : email_body_part list option; 285 + attachments : email_body_part list option; 286 + headers : header list option; 287 + } 288 + 289 + (** Email body part. See RFC8621 Section 4.1.4. *) 290 + and email_body_part = { 291 + part_id : string option; 292 + blob_id : id option; 293 + size : unsigned_int option; 294 + headers : header list option; 295 + name : string option; 296 + type_ : string option; 297 + charset : string option; 298 + disposition : string option; 299 + cid : string option; 300 + language : string list option; 301 + location : string option; 302 + sub_parts : email_body_part list option; 303 + header_parameter_name : string option; 304 + header_parameter_value : string option; 305 + } 306 + 307 + (** Email query filter condition. See RFC8621 Section 4.4. *) 308 + type email_filter_condition = { 309 + in_mailbox : id option; 310 + in_mailbox_other_than : id list option; 311 + min_size : unsigned_int option; 312 + max_size : unsigned_int option; 313 + before : utc_date option; 314 + after : utc_date option; 315 + header : (string * string) option; 316 + from : string option; 317 + to_ : string option; 318 + cc : string option; 319 + bcc : string option; 320 + subject : string option; 321 + body : string option; 322 + has_keyword : string option; 323 + not_keyword : string option; 324 + has_attachment : bool option; 325 + text : string option; 326 + } 327 + 328 + type email_query_filter = [ 329 + | `And of email_query_filter list 330 + | `Or of email_query_filter list 331 + | `Not of email_query_filter 332 + | `Condition of email_filter_condition 333 + ] 334 + 335 + (** Email/get request arguments. See RFC8621 Section 4.5. *) 336 + type email_get_arguments = { 337 + account_id : id; 338 + ids : id list option; 339 + properties : string list option; 340 + body_properties : string list option; 341 + fetch_text_body_values : bool option; 342 + fetch_html_body_values : bool option; 343 + fetch_all_body_values : bool option; 344 + max_body_value_bytes : unsigned_int option; 345 + } 346 + 347 + (** Email/get response. See RFC8621 Section 4.5. *) 348 + type email_get_response = { 349 + account_id : id; 350 + state : string; 351 + list : email list; 352 + not_found : id list; 353 + } 354 + 355 + (** Email/changes request arguments. See RFC8621 Section 4.6. *) 356 + type email_changes_arguments = { 357 + account_id : id; 358 + since_state : string; 359 + max_changes : unsigned_int option; 360 + } 361 + 362 + (** Email/changes response. See RFC8621 Section 4.6. *) 363 + type email_changes_response = { 364 + account_id : id; 365 + old_state : string; 366 + new_state : string; 367 + has_more_changes : bool; 368 + created : id list; 369 + updated : id list; 370 + destroyed : id list; 371 + } 372 + 373 + (** Email/query request arguments. See RFC8621 Section 4.4. *) 374 + type email_query_arguments = { 375 + account_id : id; 376 + filter : email_query_filter option; 377 + sort : comparator list option; 378 + collapse_threads : bool option; 379 + position : unsigned_int option; 380 + anchor : id option; 381 + anchor_offset : int_t option; 382 + limit : unsigned_int option; 383 + calculate_total : bool option; 384 + } 385 + 386 + (** Email/query response. See RFC8621 Section 4.4. *) 387 + type email_query_response = { 388 + account_id : id; 389 + query_state : string; 390 + can_calculate_changes : bool; 391 + position : unsigned_int; 392 + ids : id list; 393 + total : unsigned_int option; 394 + thread_ids : id list option; 395 + } 396 + 397 + (** Email/queryChanges request arguments. See RFC8621 Section 4.7. *) 398 + type email_query_changes_arguments = { 399 + account_id : id; 400 + filter : email_query_filter option; 401 + sort : comparator list option; 402 + collapse_threads : bool option; 403 + since_query_state : string; 404 + max_changes : unsigned_int option; 405 + up_to_id : id option; 406 + } 407 + 408 + (** Email/queryChanges response. See RFC8621 Section 4.7. *) 409 + type email_query_changes_response = { 410 + account_id : id; 411 + old_query_state : string; 412 + new_query_state : string; 413 + total : unsigned_int option; 414 + removed : id list; 415 + added : email_query_changes_added list; 416 + } 417 + 418 + and email_query_changes_added = { 419 + id : id; 420 + index : unsigned_int; 421 + } 422 + 423 + (** Email/set request arguments. See RFC8621 Section 4.8. *) 424 + type email_set_arguments = { 425 + account_id : id; 426 + if_in_state : string option; 427 + create : (id * email_creation) list option; 428 + update : (id * email_update) list option; 429 + destroy : id list option; 430 + } 431 + 432 + and email_creation = { 433 + mailbox_ids : (id * bool) list; 434 + keywords : (keyword * bool) list option; 435 + received_at : utc_date option; 436 + message_id : string list option; 437 + in_reply_to : string list option; 438 + references : string list option; 439 + sender : email_address list option; 440 + from : email_address list option; 441 + to_ : email_address list option; 442 + cc : email_address list option; 443 + bcc : email_address list option; 444 + reply_to : email_address list option; 445 + subject : string option; 446 + body_values : (string * string) list option; 447 + text_body : email_body_part list option; 448 + html_body : email_body_part list option; 449 + attachments : email_body_part list option; 450 + headers : header list option; 451 + } 452 + 453 + and email_update = { 454 + keywords : (keyword * bool) list option; 455 + mailbox_ids : (id * bool) list option; 456 + } 457 + 458 + (** Email/set response. See RFC8621 Section 4.8. *) 459 + type email_set_response = { 460 + account_id : id; 461 + old_state : string option; 462 + new_state : string; 463 + created : (id * email) list option; 464 + updated : id list option; 465 + destroyed : id list option; 466 + not_created : (id * set_error) list option; 467 + not_updated : (id * set_error) list option; 468 + not_destroyed : (id * set_error) list option; 469 + } 470 + 471 + (** Email/copy request arguments. See RFC8621 Section 4.9. *) 472 + type email_copy_arguments = { 473 + from_account_id : id; 474 + account_id : id; 475 + create : (id * email_creation) list; 476 + on_success_destroy_original : bool option; 477 + } 478 + 479 + (** Email/copy response. See RFC8621 Section 4.9. *) 480 + type email_copy_response = { 481 + from_account_id : id; 482 + account_id : id; 483 + created : (id * email) list option; 484 + not_created : (id * set_error) list option; 485 + } 486 + 487 + (** Email/import request arguments. See RFC8621 Section 4.10. *) 488 + type email_import_arguments = { 489 + account_id : id; 490 + emails : (id * email_import) list; 491 + } 492 + 493 + and email_import = { 494 + blob_id : id; 495 + mailbox_ids : (id * bool) list; 496 + keywords : (keyword * bool) list option; 497 + received_at : utc_date option; 498 + } 499 + 500 + (** Email/import response. See RFC8621 Section 4.10. *) 501 + type email_import_response = { 502 + account_id : id; 503 + created : (id * email) list option; 504 + not_created : (id * set_error) list option; 505 + } 506 + 507 + (** {1:search_snippet Search snippets} *) 508 + 509 + (** SearchSnippet/get request arguments. See RFC8621 Section 4.11. *) 510 + type search_snippet_get_arguments = { 511 + account_id : id; 512 + email_ids : id list; 513 + filter : email_filter_condition; 514 + } 515 + 516 + (** SearchSnippet/get response. See RFC8621 Section 4.11. *) 517 + type search_snippet_get_response = { 518 + account_id : id; 519 + list : (id * search_snippet) list; 520 + not_found : id list; 521 + } 522 + 523 + and search_snippet = { 524 + subject : string option; 525 + preview : string option; 526 + } 527 + 528 + (** {1:submission EmailSubmission objects} *) 529 + 530 + (** EmailSubmission address. See RFC8621 Section 5.1. *) 531 + type submission_address = { 532 + email : string; 533 + parameters : (string * string) list option; 534 + } 535 + 536 + (** Email submission object. See RFC8621 Section 5.1. *) 537 + type email_submission = { 538 + id : id; 539 + identity_id : id; 540 + email_id : id; 541 + thread_id : id; 542 + envelope : envelope option; 543 + send_at : utc_date option; 544 + undo_status : [ 545 + | `pending 546 + | `final 547 + | `canceled 548 + ] option; 549 + delivery_status : (string * submission_status) list option; 550 + dsn_blob_ids : (string * id) list option; 551 + mdn_blob_ids : (string * id) list option; 552 + } 553 + 554 + (** Envelope for mail submission. See RFC8621 Section 5.1. *) 555 + and envelope = { 556 + mail_from : submission_address; 557 + rcpt_to : submission_address list; 558 + } 559 + 560 + (** Delivery status for submitted email. See RFC8621 Section 5.1. *) 561 + and submission_status = { 562 + smtp_reply : string; 563 + delivered : string option; 564 + } 565 + 566 + (** EmailSubmission/get request arguments. See RFC8621 Section 5.3. *) 567 + type email_submission_get_arguments = { 568 + account_id : id; 569 + ids : id list option; 570 + properties : string list option; 571 + } 572 + 573 + (** EmailSubmission/get response. See RFC8621 Section 5.3. *) 574 + type email_submission_get_response = { 575 + account_id : id; 576 + state : string; 577 + list : email_submission list; 578 + not_found : id list; 579 + } 580 + 581 + (** EmailSubmission/changes request arguments. See RFC8621 Section 5.4. *) 582 + type email_submission_changes_arguments = { 583 + account_id : id; 584 + since_state : string; 585 + max_changes : unsigned_int option; 586 + } 587 + 588 + (** EmailSubmission/changes response. See RFC8621 Section 5.4. *) 589 + type email_submission_changes_response = { 590 + account_id : id; 591 + old_state : string; 592 + new_state : string; 593 + has_more_changes : bool; 594 + created : id list; 595 + updated : id list; 596 + destroyed : id list; 597 + } 598 + 599 + (** EmailSubmission/query filter condition. See RFC8621 Section 5.5. *) 600 + type email_submission_filter_condition = { 601 + identity_id : id option; 602 + email_id : id option; 603 + thread_id : id option; 604 + before : utc_date option; 605 + after : utc_date option; 606 + subject : string option; 607 + } 608 + 609 + type email_submission_query_filter = [ 610 + | `And of email_submission_query_filter list 611 + | `Or of email_submission_query_filter list 612 + | `Not of email_submission_query_filter 613 + | `Condition of email_submission_filter_condition 614 + ] 615 + 616 + (** EmailSubmission/query request arguments. See RFC8621 Section 5.5. *) 617 + type email_submission_query_arguments = { 618 + account_id : id; 619 + filter : email_submission_query_filter option; 620 + sort : comparator list option; 621 + position : unsigned_int option; 622 + anchor : id option; 623 + anchor_offset : int_t option; 624 + limit : unsigned_int option; 625 + calculate_total : bool option; 626 + } 627 + 628 + (** EmailSubmission/query response. See RFC8621 Section 5.5. *) 629 + type email_submission_query_response = { 630 + account_id : id; 631 + query_state : string; 632 + can_calculate_changes : bool; 633 + position : unsigned_int; 634 + ids : id list; 635 + total : unsigned_int option; 636 + } 637 + 638 + (** EmailSubmission/set request arguments. See RFC8621 Section 5.6. *) 639 + type email_submission_set_arguments = { 640 + account_id : id; 641 + if_in_state : string option; 642 + create : (id * email_submission_creation) list option; 643 + update : (id * email_submission_update) list option; 644 + destroy : id list option; 645 + on_success_update_email : (id * email_update) list option; 646 + } 647 + 648 + and email_submission_creation = { 649 + email_id : id; 650 + identity_id : id; 651 + envelope : envelope option; 652 + send_at : utc_date option; 653 + } 654 + 655 + and email_submission_update = { 656 + email_id : id option; 657 + identity_id : id option; 658 + envelope : envelope option; 659 + undo_status : [`canceled] option; 660 + } 661 + 662 + (** EmailSubmission/set response. See RFC8621 Section 5.6. *) 663 + type email_submission_set_response = { 664 + account_id : id; 665 + old_state : string option; 666 + new_state : string; 667 + created : (id * email_submission) list option; 668 + updated : id list option; 669 + destroyed : id list option; 670 + not_created : (id * set_error) list option; 671 + not_updated : (id * set_error) list option; 672 + not_destroyed : (id * set_error) list option; 673 + } 674 + 675 + (** {1:identity Identity objects} *) 676 + 677 + (** Identity for sending mail. See RFC8621 Section 6. *) 678 + type identity = { 679 + id : id; 680 + name : string; 681 + email : string; 682 + reply_to : email_address list option; 683 + bcc : email_address list option; 684 + text_signature : string option; 685 + html_signature : string option; 686 + may_delete : bool; 687 + } 688 + 689 + (** Identity/get request arguments. See RFC8621 Section 6.1. *) 690 + type identity_get_arguments = { 691 + account_id : id; 692 + ids : id list option; 693 + properties : string list option; 694 + } 695 + 696 + (** Identity/get response. See RFC8621 Section 6.1. *) 697 + type identity_get_response = { 698 + account_id : id; 699 + state : string; 700 + list : identity list; 701 + not_found : id list; 702 + } 703 + 704 + (** Identity/changes request arguments. See RFC8621 Section 6.2. *) 705 + type identity_changes_arguments = { 706 + account_id : id; 707 + since_state : string; 708 + max_changes : unsigned_int option; 709 + } 710 + 711 + (** Identity/changes response. See RFC8621 Section 6.2. *) 712 + type identity_changes_response = { 713 + account_id : id; 714 + old_state : string; 715 + new_state : string; 716 + has_more_changes : bool; 717 + created : id list; 718 + updated : id list; 719 + destroyed : id list; 720 + } 721 + 722 + (** Identity/set request arguments. See RFC8621 Section 6.3. *) 723 + type identity_set_arguments = { 724 + account_id : id; 725 + if_in_state : string option; 726 + create : (id * identity_creation) list option; 727 + update : (id * identity_update) list option; 728 + destroy : id list option; 729 + } 730 + 731 + and identity_creation = { 732 + name : string; 733 + email : string; 734 + reply_to : email_address list option; 735 + bcc : email_address list option; 736 + text_signature : string option; 737 + html_signature : string option; 738 + } 739 + 740 + and identity_update = { 741 + name : string option; 742 + email : string option; 743 + reply_to : email_address list option; 744 + bcc : email_address list option; 745 + text_signature : string option; 746 + html_signature : string option; 747 + } 748 + 749 + (** Identity/set response. See RFC8621 Section 6.3. *) 750 + type identity_set_response = { 751 + account_id : id; 752 + old_state : string option; 753 + new_state : string; 754 + created : (id * identity) list option; 755 + updated : id list option; 756 + destroyed : id list option; 757 + not_created : (id * set_error) list option; 758 + not_updated : (id * set_error) list option; 759 + not_destroyed : (id * set_error) list option; 760 + } 761 + 762 + (** {1:vacation_response VacationResponse objects} *) 763 + 764 + (** Vacation auto-reply setting. See RFC8621 Section 7. *) 765 + type vacation_response = { 766 + id : id; 767 + is_enabled : bool; 768 + from_date : utc_date option; 769 + to_date : utc_date option; 770 + subject : string option; 771 + text_body : string option; 772 + html_body : string option; 773 + } 774 + 775 + (** VacationResponse/get request arguments. See RFC8621 Section 7.2. *) 776 + type vacation_response_get_arguments = { 777 + account_id : id; 778 + ids : id list option; 779 + properties : string list option; 780 + } 781 + 782 + (** VacationResponse/get response. See RFC8621 Section 7.2. *) 783 + type vacation_response_get_response = { 784 + account_id : id; 785 + state : string; 786 + list : vacation_response list; 787 + not_found : id list; 788 + } 789 + 790 + (** VacationResponse/set request arguments. See RFC8621 Section 7.3. *) 791 + type vacation_response_set_arguments = { 792 + account_id : id; 793 + if_in_state : string option; 794 + update : (id * vacation_response_update) list; 795 + } 796 + 797 + and vacation_response_update = { 798 + is_enabled : bool option; 799 + from_date : utc_date option; 800 + to_date : utc_date option; 801 + subject : string option; 802 + text_body : string option; 803 + html_body : string option; 804 + } 805 + 806 + (** VacationResponse/set response. See RFC8621 Section 7.3. *) 807 + type vacation_response_set_response = { 808 + account_id : id; 809 + old_state : string option; 810 + new_state : string; 811 + updated : id list option; 812 + not_updated : (id * set_error) list option; 813 + } 814 + end 815 + 816 + (** {1 JSON serialization} *) 817 + 818 + module Json : sig 819 + open Types 820 + 821 + (** {2 Helper functions for serialization} *) 822 + 823 + val string_of_mailbox_role : mailbox_role -> string 824 + val mailbox_role_of_string : string -> mailbox_role 825 + 826 + val string_of_keyword : keyword -> string 827 + val keyword_of_string : string -> keyword 828 + 829 + (** {2 Mailbox serialization} *) 830 + 831 + (** TODO:claude - Need to implement all JSON serialization functions 832 + for each type we've defined. This would be a substantial amount of 833 + code and likely require additional understanding of the ezjsonm API. 834 + 835 + The interface would include functions like: 836 + 837 + val mailbox_to_json : mailbox -> Ezjsonm.value 838 + val mailbox_of_json : Ezjsonm.value -> mailbox result 839 + 840 + And similarly for all other types. 841 + *) 842 + end 843 + 844 + (** {1 API functions} *) 845 + 846 + (** TODO:claude - Need to implement API functions for interacting with the 847 + mail-specific JMAP server endpoints. These would use the Jmap.Api module 848 + to make HTTP requests and parse responses. 849 + 850 + The interface would include functions like: 851 + 852 + val get_mailboxes : Jmap.Api.session -> ?ids:id list -> ?properties:string list -> account_id:id -> (mailbox_get_response, error) result Lwt.t 853 + 854 + And similarly for all other API operations. 855 + *)