···
1
+
(** Implementation of the JMAP Mail extension, as defined in RFC8621 *)
3
+
module Types = struct
6
+
(** {1 Mail capabilities} *)
8
+
(** Capability URI for JMAP Mail*)
9
+
let capability_mail = "urn:ietf:params:jmap:mail"
11
+
(** Capability URI for JMAP Submission *)
12
+
let capability_submission = "urn:ietf:params:jmap:submission"
14
+
(** Capability URI for JMAP Vacation Response *)
15
+
let capability_vacation_response = "urn:ietf:params:jmap:vacationresponse"
17
+
(** {1:mailbox Mailbox objects} *)
19
+
(** A role for a mailbox. See RFC8621 Section 2. *)
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 *)
32
+
(** A mailbox (folder) in a mail account. See RFC8621 Section 2. *)
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;
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;
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;
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
76
+
(** Mailbox/get request arguments. See RFC8621 Section 2.1. *)
77
+
type mailbox_get_arguments = {
79
+
ids : id list option;
80
+
properties : string list option;
83
+
(** Mailbox/get response. See RFC8621 Section 2.1. *)
84
+
type mailbox_get_response = {
87
+
list : mailbox list;
88
+
not_found : id list;
91
+
(** Mailbox/changes request arguments. See RFC8621 Section 2.2. *)
92
+
type mailbox_changes_arguments = {
94
+
since_state : string;
95
+
max_changes : unsigned_int option;
98
+
(** Mailbox/changes response. See RFC8621 Section 2.2. *)
99
+
type mailbox_changes_response = {
101
+
old_state : string;
102
+
new_state : string;
103
+
has_more_changes : bool;
106
+
destroyed : id list;
109
+
(** Mailbox/query request arguments. See RFC8621 Section 2.3. *)
110
+
type mailbox_query_arguments = {
112
+
filter : mailbox_query_filter option;
113
+
sort : [ `name | `role | `sort_order ] list option;
114
+
limit : unsigned_int option;
117
+
(** Mailbox/query response. See RFC8621 Section 2.3. *)
118
+
type mailbox_query_response = {
120
+
query_state : string;
121
+
can_calculate_changes : bool;
122
+
position : unsigned_int;
124
+
total : unsigned_int option;
127
+
(** Mailbox/queryChanges request arguments. See RFC8621 Section 2.4. *)
128
+
type mailbox_query_changes_arguments = {
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;
137
+
(** Mailbox/queryChanges response. See RFC8621 Section 2.4. *)
138
+
type mailbox_query_changes_response = {
140
+
old_query_state : string;
141
+
new_query_state : string;
142
+
total : unsigned_int option;
144
+
added : mailbox_query_changes_added list;
147
+
and mailbox_query_changes_added = {
149
+
index : unsigned_int;
152
+
(** Mailbox/set request arguments. See RFC8621 Section 2.5. *)
153
+
type mailbox_set_arguments = {
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;
161
+
and mailbox_creation = {
163
+
parent_id : id option;
164
+
role : string option;
165
+
sort_order : unsigned_int option;
166
+
is_subscribed : bool option;
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;
177
+
(** Mailbox/set response. See RFC8621 Section 2.5. *)
178
+
type mailbox_set_response = {
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;
190
+
(** {1:thread Thread objects} *)
192
+
(** A thread in a mail account. See RFC8621 Section 3. *)
195
+
email_ids : id list;
198
+
(** Thread/get request arguments. See RFC8621 Section 3.1. *)
199
+
type thread_get_arguments = {
201
+
ids : id list option;
202
+
properties : string list option;
205
+
(** Thread/get response. See RFC8621 Section 3.1. *)
206
+
type thread_get_response = {
209
+
list : thread list;
210
+
not_found : id list;
213
+
(** Thread/changes request arguments. See RFC8621 Section 3.2. *)
214
+
type thread_changes_arguments = {
216
+
since_state : string;
217
+
max_changes : unsigned_int option;
220
+
(** Thread/changes response. See RFC8621 Section 3.2. *)
221
+
type thread_changes_response = {
223
+
old_state : string;
224
+
new_state : string;
225
+
has_more_changes : bool;
228
+
destroyed : id list;
231
+
(** {1:email Email objects} *)
233
+
(** Addressing (mailbox) information. See RFC8621 Section 4.1.1. *)
234
+
type email_address = {
235
+
name : string option;
237
+
parameters : (string * string) list;
240
+
(** Message header field. See RFC8621 Section 4.1.2. *)
246
+
(** Email keyword (flag). See RFC8621 Section 4.3. *)
259
+
(** Email message. See RFC8621 Section 4. *)
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;
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;
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;
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
334
+
(** Email/get request arguments. See RFC8621 Section 4.5. *)
335
+
type email_get_arguments = {
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;
346
+
(** Email/get response. See RFC8621 Section 4.5. *)
347
+
type email_get_response = {
351
+
not_found : id list;
354
+
(** Email/changes request arguments. See RFC8621 Section 4.6. *)
355
+
type email_changes_arguments = {
357
+
since_state : string;
358
+
max_changes : unsigned_int option;
361
+
(** Email/changes response. See RFC8621 Section 4.6. *)
362
+
type email_changes_response = {
364
+
old_state : string;
365
+
new_state : string;
366
+
has_more_changes : bool;
369
+
destroyed : id list;
372
+
(** Email/query request arguments. See RFC8621 Section 4.4. *)
373
+
type email_query_arguments = {
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;
385
+
(** Email/query response. See RFC8621 Section 4.4. *)
386
+
type email_query_response = {
388
+
query_state : string;
389
+
can_calculate_changes : bool;
390
+
position : unsigned_int;
392
+
total : unsigned_int option;
393
+
thread_ids : id list option;
396
+
(** Email/queryChanges request arguments. See RFC8621 Section 4.7. *)
397
+
type email_query_changes_arguments = {
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;
407
+
(** Email/queryChanges response. See RFC8621 Section 4.7. *)
408
+
type email_query_changes_response = {
410
+
old_query_state : string;
411
+
new_query_state : string;
412
+
total : unsigned_int option;
414
+
added : email_query_changes_added list;
417
+
and email_query_changes_added = {
419
+
index : unsigned_int;
422
+
(** Email/set request arguments. See RFC8621 Section 4.8. *)
423
+
type email_set_arguments = {
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;
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;
452
+
and email_update = {
453
+
keywords : (keyword * bool) list option;
454
+
mailbox_ids : (id * bool) list option;
457
+
(** Email/set response. See RFC8621 Section 4.8. *)
458
+
type email_set_response = {
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;
470
+
(** Email/copy request arguments. See RFC8621 Section 4.9. *)
471
+
type email_copy_arguments = {
472
+
from_account_id : id;
474
+
create : (id * email_creation) list;
475
+
on_success_destroy_original : bool option;
478
+
(** Email/copy response. See RFC8621 Section 4.9. *)
479
+
type email_copy_response = {
480
+
from_account_id : id;
482
+
created : (id * email) list option;
483
+
not_created : (id * set_error) list option;
486
+
(** Email/import request arguments. See RFC8621 Section 4.10. *)
487
+
type email_import_arguments = {
489
+
emails : (id * email_import) list;
492
+
and email_import = {
494
+
mailbox_ids : (id * bool) list;
495
+
keywords : (keyword * bool) list option;
496
+
received_at : utc_date option;
499
+
(** Email/import response. See RFC8621 Section 4.10. *)
500
+
type email_import_response = {
502
+
created : (id * email) list option;
503
+
not_created : (id * set_error) list option;
506
+
(** {1:search_snippet Search snippets} *)
508
+
(** SearchSnippet/get request arguments. See RFC8621 Section 4.11. *)
509
+
type search_snippet_get_arguments = {
511
+
email_ids : id list;
512
+
filter : email_filter_condition;
515
+
(** SearchSnippet/get response. See RFC8621 Section 4.11. *)
516
+
type search_snippet_get_response = {
518
+
list : (id * search_snippet) list;
519
+
not_found : id list;
522
+
and search_snippet = {
523
+
subject : string option;
524
+
preview : string option;
527
+
(** {1:submission EmailSubmission objects} *)
529
+
(** EmailSubmission address. See RFC8621 Section 5.1. *)
530
+
type submission_address = {
532
+
parameters : (string * string) list option;
535
+
(** Email submission object. See RFC8621 Section 5.1. *)
536
+
type email_submission = {
541
+
envelope : envelope option;
542
+
send_at : utc_date 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;
553
+
(** Envelope for mail submission. See RFC8621 Section 5.1. *)
555
+
mail_from : submission_address;
556
+
rcpt_to : submission_address list;
559
+
(** Delivery status for submitted email. See RFC8621 Section 5.1. *)
560
+
and submission_status = {
561
+
smtp_reply : string;
562
+
delivered : string option;
565
+
(** EmailSubmission/get request arguments. See RFC8621 Section 5.3. *)
566
+
type email_submission_get_arguments = {
568
+
ids : id list option;
569
+
properties : string list option;
572
+
(** EmailSubmission/get response. See RFC8621 Section 5.3. *)
573
+
type email_submission_get_response = {
576
+
list : email_submission list;
577
+
not_found : id list;
580
+
(** EmailSubmission/changes request arguments. See RFC8621 Section 5.4. *)
581
+
type email_submission_changes_arguments = {
583
+
since_state : string;
584
+
max_changes : unsigned_int option;
587
+
(** EmailSubmission/changes response. See RFC8621 Section 5.4. *)
588
+
type email_submission_changes_response = {
590
+
old_state : string;
591
+
new_state : string;
592
+
has_more_changes : bool;
595
+
destroyed : id list;
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;
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
615
+
(** EmailSubmission/query request arguments. See RFC8621 Section 5.5. *)
616
+
type email_submission_query_arguments = {
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;
627
+
(** EmailSubmission/query response. See RFC8621 Section 5.5. *)
628
+
type email_submission_query_response = {
630
+
query_state : string;
631
+
can_calculate_changes : bool;
632
+
position : unsigned_int;
634
+
total : unsigned_int option;
637
+
(** EmailSubmission/set request arguments. See RFC8621 Section 5.6. *)
638
+
type email_submission_set_arguments = {
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;
647
+
and email_submission_creation = {
650
+
envelope : envelope option;
651
+
send_at : utc_date option;
654
+
and email_submission_update = {
655
+
email_id : id option;
656
+
identity_id : id option;
657
+
envelope : envelope option;
658
+
undo_status : [`canceled] option;
661
+
(** EmailSubmission/set response. See RFC8621 Section 5.6. *)
662
+
type email_submission_set_response = {
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;
674
+
(** {1:identity Identity objects} *)
676
+
(** Identity for sending mail. See RFC8621 Section 6. *)
681
+
reply_to : email_address list option;
682
+
bcc : email_address list option;
683
+
text_signature : string option;
684
+
html_signature : string option;
688
+
(** Identity/get request arguments. See RFC8621 Section 6.1. *)
689
+
type identity_get_arguments = {
691
+
ids : id list option;
692
+
properties : string list option;
695
+
(** Identity/get response. See RFC8621 Section 6.1. *)
696
+
type identity_get_response = {
699
+
list : identity list;
700
+
not_found : id list;
703
+
(** Identity/changes request arguments. See RFC8621 Section 6.2. *)
704
+
type identity_changes_arguments = {
706
+
since_state : string;
707
+
max_changes : unsigned_int option;
710
+
(** Identity/changes response. See RFC8621 Section 6.2. *)
711
+
type identity_changes_response = {
713
+
old_state : string;
714
+
new_state : string;
715
+
has_more_changes : bool;
718
+
destroyed : id list;
721
+
(** Identity/set request arguments. See RFC8621 Section 6.3. *)
722
+
type identity_set_arguments = {
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;
730
+
and identity_creation = {
733
+
reply_to : email_address list option;
734
+
bcc : email_address list option;
735
+
text_signature : string option;
736
+
html_signature : string option;
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;
748
+
(** Identity/set response. See RFC8621 Section 6.3. *)
749
+
type identity_set_response = {
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;
761
+
(** {1:vacation_response VacationResponse objects} *)
763
+
(** Vacation auto-reply setting. See RFC8621 Section 7. *)
764
+
type vacation_response = {
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;
774
+
(** VacationResponse/get request arguments. See RFC8621 Section 7.2. *)
775
+
type vacation_response_get_arguments = {
777
+
ids : id list option;
778
+
properties : string list option;
781
+
(** VacationResponse/get response. See RFC8621 Section 7.2. *)
782
+
type vacation_response_get_response = {
785
+
list : vacation_response list;
786
+
not_found : id list;
789
+
(** VacationResponse/set request arguments. See RFC8621 Section 7.3. *)
790
+
type vacation_response_set_arguments = {
792
+
if_in_state : string option;
793
+
update : (id * vacation_response_update) list;
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;
805
+
(** VacationResponse/set response. See RFC8621 Section 7.3. *)
806
+
type vacation_response_set_response = {
808
+
old_state : string option;
809
+
new_state : string;
810
+
updated : id list option;
811
+
not_updated : (id * set_error) list option;
815
+
(** {1 JSON serialization} *)
817
+
module Json = struct
820
+
(** {2 Helper functions for serialization} *)
822
+
let string_of_mailbox_role = function
824
+
| Archive -> "archive"
825
+
| Drafts -> "drafts"
826
+
| Flagged -> "flagged"
827
+
| Important -> "important"
834
+
let mailbox_role_of_string = function
836
+
| "archive" -> Archive
837
+
| "drafts" -> Drafts
838
+
| "flagged" -> Flagged
839
+
| "important" -> Important
846
+
let string_of_keyword = function
847
+
| Flagged -> "$flagged"
848
+
| Answered -> "$answered"
849
+
| Draft -> "$draft"
850
+
| Forwarded -> "$forwarded"
851
+
| Phishing -> "$phishing"
853
+
| NotJunk -> "$notjunk"
855
+
| Unread -> "$unread"
858
+
let keyword_of_string = function
859
+
| "$flagged" -> Flagged
860
+
| "$answered" -> Answered
861
+
| "$draft" -> Draft
862
+
| "$forwarded" -> Forwarded
863
+
| "$phishing" -> Phishing
865
+
| "$notjunk" -> NotJunk
867
+
| "$unread" -> Unread
870
+
(** {2 Mailbox serialization} *)
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.
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
888
+
(** {1 API functions} *)
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.
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
900
+
- Identity management
901
+
- Vacation response management