this repo has no description
1(** JMAP Mail Extension Library (RFC 8621).
2
3 This library extends the core JMAP protocol with email-specific
4 functionality as defined in RFC 8621. It provides types and signatures
5 for interacting with JMAP Mail data types: Mailbox, Thread, Email,
6 SearchSnippet, Identity, EmailSubmission, and VacationResponse.
7
8 Requires the core Jmap library and Jmap_unix library for network operations.
9
10 @see <https://www.rfc-editor.org/rfc/rfc8621.html> RFC 8621: JMAP for Mail
11*)
12
13open Jmap.Types
14
15(** {1 Core Types} *)
16module Types = Jmap_email_types
17
18(** {1 Mailbox}
19 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-2> RFC 8621, Section 2 *)
20module Mailbox = Jmap_mailbox
21
22(** {1 Thread}
23 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-3> RFC 8621, Section 3 *)
24module Thread = Jmap_thread
25
26(** {1 Search Snippet}
27 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-5> RFC 8621, Section 5 *)
28module SearchSnippet = Jmap_search_snippet
29
30(** {1 Identity}
31 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-6> RFC 8621, Section 6 *)
32module Identity = Jmap_identity
33
34(** {1 Email Submission}
35 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-7> RFC 8621, Section 7 *)
36module Submission = Jmap_submission
37
38(** {1 Vacation Response}
39 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-8> RFC 8621, Section 8 *)
40module Vacation = Jmap_vacation
41
42(** {1 Example Usage}
43
44 The following example demonstrates using the JMAP Email library to fetch unread emails
45 from a specific sender.
46
47{[
48 (* OCaml 5.1 required for Lwt let operators *)
49 open Lwt.Syntax
50 open Jmap
51 open Jmap.Types
52 open Jmap.Wire
53 open Jmap.Methods
54 open Jmap_email
55 open Jmap.Unix
56
57 let list_unread_from_sender ctx session sender_email =
58 (* Find the primary mail account *)
59 let primary_mail_account_id =
60 Hashtbl.find session.primary_accounts capability_mail
61 in
62 (* Construct the filter *)
63 let filter : filter =
64 Filter_operator (Filter_operator.v
65 ~operator:`AND
66 ~conditions:[
67 Filter_condition (Yojson.Safe.to_basic (`Assoc [
68 ("from", `String sender_email);
69 ]));
70 Filter_condition (Yojson.Safe.to_basic (`Assoc [
71 ("hasKeyword", `String keyword_seen);
72 ("value", `Bool false);
73 ]));
74 ]
75 ())
76 in
77 (* Prepare the Email/query invocation *)
78 let query_args = Query_args.v
79 ~account_id:primary_mail_account_id
80 ~filter
81 ~sort:[
82 Comparator.v
83 ~property:"receivedAt"
84 ~is_ascending:false
85 ()
86 ]
87 ~position:0
88 ~limit:20 (* Get latest 20 *)
89 ~calculate_total:false
90 ~collapse_threads:false
91 ()
92 in
93 let query_invocation = Invocation.v
94 ~method_name:"Email/query"
95 ~arguments:(* Yojson conversion of query_args needed here *)
96 ~method_call_id:"q1"
97 ()
98 in
99
100 (* Prepare the Email/get invocation using a back-reference *)
101 let get_args = Get_args.v
102 ~account_id:primary_mail_account_id
103 ~properties:["id"; "subject"; "receivedAt"; "from"]
104 ()
105 in
106 let get_invocation = Invocation.v
107 ~method_name:"Email/get"
108 ~arguments:(* Yojson conversion of get_args, with ids replaced by a ResultReference to q1 needed here *)
109 ~method_call_id:"g1"
110 ()
111 in
112
113 (* Prepare the JMAP request *)
114 let request = Request.v
115 ~using:[ Jmap.capability_core; capability_mail ]
116 ~method_calls:[ query_invocation; get_invocation ]
117 ()
118 in
119
120 (* Send the request *)
121 let* response = Jmap.Unix.request ctx request in
122
123 (* Process the response (extract Email/get results) *)
124 (* ... Omitted: find the Email/get response in response.method_responses ... *)
125 Lwt.return_unit
126]}
127*)
128
129(** Capability URI for JMAP Mail.
130 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-1.3.1> RFC 8621, Section 1.3.1 *)
131val capability_mail : string
132
133(** Capability URI for JMAP Submission.
134 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-1.3.2> RFC 8621, Section 1.3.2 *)
135val capability_submission : string
136
137(** Capability URI for JMAP Vacation Response.
138 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-1.3.3> RFC 8621, Section 1.3.3 *)
139val capability_vacationresponse : string
140
141(** Type name for EmailDelivery push notifications.
142 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-1.5> RFC 8621, Section 1.5 *)
143val push_event_type_email_delivery : string
144
145(** Keyword string constants for JMAP email flags.
146 Provides easy access to standardized keyword string values.
147 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-4.1.1> RFC 8621, Section 4.1.1 *)
148module Keyword : sig
149 (** {1 IMAP System Flags} *)
150
151 (** "$draft": The Email is a draft the user is composing *)
152 val draft : string
153
154 (** "$seen": The Email has been read *)
155 val seen : string
156
157 (** "$flagged": The Email has been flagged for urgent/special attention *)
158 val flagged : string
159
160 (** "$answered": The Email has been replied to *)
161 val answered : string
162
163 (** {1 Common Extension Keywords} *)
164
165 (** "$forwarded": The Email has been forwarded *)
166 val forwarded : string
167
168 (** "$phishing": The Email is likely to be phishing *)
169 val phishing : string
170
171 (** "$junk": The Email is spam/junk *)
172 val junk : string
173
174 (** "$notjunk": The Email is explicitly marked as not spam/junk *)
175 val notjunk : string
176
177 (** {1 Apple Mail and Vendor Extensions}
178 @see <https://datatracker.ietf.org/doc/draft-ietf-mailmaint-messageflag-mailboxattribute/> *)
179
180 (** "$notify": Request to be notified when this email gets a reply *)
181 val notify : string
182
183 (** "$muted": Email is muted (notifications disabled) *)
184 val muted : string
185
186 (** "$followed": Email thread is followed for notifications *)
187 val followed : string
188
189 (** "$memo": Email has a memo/note associated with it *)
190 val memo : string
191
192 (** "$hasmemo": Email has a memo, annotation or note property *)
193 val hasmemo : string
194
195 (** "$autosent": Email was generated or sent automatically *)
196 val autosent : string
197
198 (** "$unsubscribed": User has unsubscribed from this sender *)
199 val unsubscribed : string
200
201 (** "$canunsubscribe": Email contains unsubscribe information *)
202 val canunsubscribe : string
203
204 (** "$imported": Email was imported from another system *)
205 val imported : string
206
207 (** "$istrusted": Email is from a trusted/verified sender *)
208 val istrusted : string
209
210 (** "$maskedemail": Email is to/from a masked/anonymous address *)
211 val maskedemail : string
212
213 (** "$new": Email was recently delivered *)
214 val new_mail : string
215
216 (** {1 Apple Mail Color Flag Bits} *)
217
218 (** "$MailFlagBit0": First color flag bit (red) *)
219 val mailflagbit0 : string
220
221 (** "$MailFlagBit1": Second color flag bit (orange) *)
222 val mailflagbit1 : string
223
224 (** "$MailFlagBit2": Third color flag bit (yellow) *)
225 val mailflagbit2 : string
226
227 (** {1 Color Flag Combinations} *)
228
229 (** Get color flag bit values for a specific color
230 @return A list of flags to set to create the requested color *)
231 val color_flags : [`Red | `Orange | `Yellow | `Green | `Blue | `Purple | `Gray] -> string list
232
233 (** Check if a string is a valid keyword according to the RFC
234 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-4.1.1> RFC 8621, Section 4.1.1 *)
235 val is_valid : string -> bool
236end
237
238(** For backward compatibility - DEPRECATED, use Keyword.draft instead *)
239val keyword_draft : string
240
241(** For backward compatibility - DEPRECATED, use Keyword.seen instead *)
242val keyword_seen : string
243
244(** For backward compatibility - DEPRECATED, use Keyword.flagged instead *)
245val keyword_flagged : string
246
247(** For backward compatibility - DEPRECATED, use Keyword.answered instead *)
248val keyword_answered : string
249
250(** For backward compatibility - DEPRECATED, use Keyword.forwarded instead *)
251val keyword_forwarded : string
252
253(** For backward compatibility - DEPRECATED, use Keyword.phishing instead *)
254val keyword_phishing : string
255
256(** For backward compatibility - DEPRECATED, use Keyword.junk instead *)
257val keyword_junk : string
258
259(** For backward compatibility - DEPRECATED, use Keyword.notjunk instead *)
260val keyword_notjunk : string
261
262(** Email keyword operations.
263 Functions to manipulate and update email keywords/flags. *)
264module Keyword_ops : sig
265 (** Add a keyword/flag to an email *)
266 val add : Types.Email.t -> Types.Keywords.keyword -> Types.Email.t
267
268 (** Remove a keyword/flag from an email *)
269 val remove : Types.Email.t -> Types.Keywords.keyword -> Types.Email.t
270
271 (** {1 System Flag Operations} *)
272
273 (** Mark an email as seen/read *)
274 val mark_as_seen : Types.Email.t -> Types.Email.t
275
276 (** Mark an email as unseen/unread *)
277 val mark_as_unseen : Types.Email.t -> Types.Email.t
278
279 (** Mark an email as flagged/important *)
280 val mark_as_flagged : Types.Email.t -> Types.Email.t
281
282 (** Remove flagged/important marking from an email *)
283 val unmark_flagged : Types.Email.t -> Types.Email.t
284
285 (** Mark an email as a draft *)
286 val mark_as_draft : Types.Email.t -> Types.Email.t
287
288 (** Remove draft marking from an email *)
289 val unmark_draft : Types.Email.t -> Types.Email.t
290
291 (** Mark an email as answered/replied *)
292 val mark_as_answered : Types.Email.t -> Types.Email.t
293
294 (** Remove answered/replied marking from an email *)
295 val unmark_answered : Types.Email.t -> Types.Email.t
296
297 (** Mark an email as forwarded *)
298 val mark_as_forwarded : Types.Email.t -> Types.Email.t
299
300 (** Mark an email as spam/junk *)
301 val mark_as_junk : Types.Email.t -> Types.Email.t
302
303 (** Mark an email as not spam/junk *)
304 val mark_as_not_junk : Types.Email.t -> Types.Email.t
305
306 (** Mark an email as phishing *)
307 val mark_as_phishing : Types.Email.t -> Types.Email.t
308
309 (** {1 Extension Flag Operations} *)
310
311 (** Mark an email for notification when replied to *)
312 val mark_as_notify : Types.Email.t -> Types.Email.t
313
314 (** Remove notification flag from an email *)
315 val unmark_notify : Types.Email.t -> Types.Email.t
316
317 (** Mark an email as muted (no notifications) *)
318 val mark_as_muted : Types.Email.t -> Types.Email.t
319
320 (** Unmute an email (allow notifications) *)
321 val unmark_muted : Types.Email.t -> Types.Email.t
322
323 (** Mark an email thread as followed for notifications *)
324 val mark_as_followed : Types.Email.t -> Types.Email.t
325
326 (** Remove followed status from an email thread *)
327 val unmark_followed : Types.Email.t -> Types.Email.t
328
329 (** Mark an email with a memo *)
330 val mark_as_memo : Types.Email.t -> Types.Email.t
331
332 (** Mark an email with the hasmemo flag *)
333 val mark_as_hasmemo : Types.Email.t -> Types.Email.t
334
335 (** Mark an email as automatically sent *)
336 val mark_as_autosent : Types.Email.t -> Types.Email.t
337
338 (** Mark an email as being from an unsubscribed sender *)
339 val mark_as_unsubscribed : Types.Email.t -> Types.Email.t
340
341 (** Mark an email as having unsubscribe capability *)
342 val mark_as_canunsubscribe : Types.Email.t -> Types.Email.t
343
344 (** Mark an email as imported from another system *)
345 val mark_as_imported : Types.Email.t -> Types.Email.t
346
347 (** Mark an email as from a trusted/verified sender *)
348 val mark_as_trusted : Types.Email.t -> Types.Email.t
349
350 (** Mark an email as having masked/anonymous address *)
351 val mark_as_maskedemail : Types.Email.t -> Types.Email.t
352
353 (** Mark an email as new/recent *)
354 val mark_as_new : Types.Email.t -> Types.Email.t
355
356 (** Remove new/recent flag from an email *)
357 val unmark_new : Types.Email.t -> Types.Email.t
358
359 (** {1 Color Flag Operations} *)
360
361 (** Set color flag bits on an email *)
362 val set_color_flags : Types.Email.t -> red:bool -> orange:bool -> yellow:bool -> Types.Email.t
363
364 (** Mark an email with a predefined color *)
365 val mark_as_color : Types.Email.t ->
366 [`Red | `Orange | `Yellow | `Green | `Blue | `Purple | `Gray] -> Types.Email.t
367
368 (** Remove all color flag bits from an email *)
369 val clear_color_flags : Types.Email.t -> Types.Email.t
370
371 (** {1 Custom Flag Operations} *)
372
373 (** Add a custom keyword to an email *)
374 val add_custom : Types.Email.t -> string -> Types.Email.t
375
376 (** Remove a custom keyword from an email *)
377 val remove_custom : Types.Email.t -> string -> Types.Email.t
378
379 (** {1 Patch Object Creation} *)
380
381 (** Create a patch object to add a keyword to emails *)
382 val add_keyword_patch : Types.Keywords.keyword -> Jmap.Methods.patch_object
383
384 (** Create a patch object to remove a keyword from emails *)
385 val remove_keyword_patch : Types.Keywords.keyword -> Jmap.Methods.patch_object
386
387 (** Create a patch object to mark emails as seen/read *)
388 val mark_seen_patch : unit -> Jmap.Methods.patch_object
389
390 (** Create a patch object to mark emails as unseen/unread *)
391 val mark_unseen_patch : unit -> Jmap.Methods.patch_object
392
393 (** Create a patch object to set a specific color on emails *)
394 val set_color_patch : [`Red | `Orange | `Yellow | `Green | `Blue | `Purple | `Gray] ->
395 Jmap.Methods.patch_object
396end
397
398(** Conversion functions for JMAP/IMAP compatibility *)
399module Conversion : sig
400 (** {1 Keyword/Flag Conversion} *)
401
402 (** Convert a JMAP keyword variant to IMAP flag *)
403 val keyword_to_imap_flag : Types.Keywords.keyword -> string
404
405 (** Convert an IMAP flag to JMAP keyword variant *)
406 val imap_flag_to_keyword : string -> Types.Keywords.keyword
407
408 (** Check if a string is valid for use as a custom keyword according to RFC 8621.
409 @deprecated Use Keyword.is_valid instead. *)
410 val is_valid_custom_keyword : string -> bool
411
412 (** Get the JMAP protocol string representation of a keyword *)
413 val keyword_to_string : Types.Keywords.keyword -> string
414
415 (** Parse a JMAP protocol string into a keyword variant *)
416 val string_to_keyword : string -> Types.Keywords.keyword
417
418 (** {1 Color Conversion} *)
419
420 (** Convert a color name to the corresponding flag bit combination *)
421 val color_to_flags : [`Red | `Orange | `Yellow | `Green | `Blue | `Purple | `Gray] ->
422 Types.Keywords.keyword list
423
424 (** Try to determine a color from a set of keywords *)
425 val keywords_to_color : Types.Keywords.t ->
426 [`Red | `Orange | `Yellow | `Green | `Blue | `Purple | `Gray | `None] option
427end
428
429(** {1 Helper Functions} *)
430
431(** Email query filter helpers *)
432module Email_filter : sig
433 (** Create a filter to find messages in a specific mailbox *)
434 val in_mailbox : id -> Jmap.Methods.Filter.t
435
436 (** Create a filter to find messages with a specific keyword/flag *)
437 val has_keyword : Types.Keywords.keyword -> Jmap.Methods.Filter.t
438
439 (** Create a filter to find messages without a specific keyword/flag *)
440 val not_has_keyword : Types.Keywords.keyword -> Jmap.Methods.Filter.t
441
442 (** Create a filter to find unread messages *)
443 val unread : unit -> Jmap.Methods.Filter.t
444
445 (** Create a filter to find messages with a specific subject *)
446 val subject : string -> Jmap.Methods.Filter.t
447
448 (** Create a filter to find messages from a specific sender *)
449 val from : string -> Jmap.Methods.Filter.t
450
451 (** Create a filter to find messages sent to a specific recipient *)
452 val to_ : string -> Jmap.Methods.Filter.t
453
454 (** Create a filter to find messages with attachments *)
455 val has_attachment : unit -> Jmap.Methods.Filter.t
456
457 (** Create a filter to find messages received before a date *)
458 val before : date -> Jmap.Methods.Filter.t
459
460 (** Create a filter to find messages received after a date *)
461 val after : date -> Jmap.Methods.Filter.t
462
463 (** Create a filter to find messages with size larger than the given bytes *)
464 val larger_than : uint -> Jmap.Methods.Filter.t
465
466 (** Create a filter to find messages with size smaller than the given bytes *)
467 val smaller_than : uint -> Jmap.Methods.Filter.t
468end
469
470(** Common email sorting comparators *)
471module Email_sort : sig
472 (** Sort by received date (most recent first) *)
473 val received_newest_first : unit -> Jmap.Methods.Comparator.t
474
475 (** Sort by received date (oldest first) *)
476 val received_oldest_first : unit -> Jmap.Methods.Comparator.t
477
478 (** Sort by sent date (most recent first) *)
479 val sent_newest_first : unit -> Jmap.Methods.Comparator.t
480
481 (** Sort by sent date (oldest first) *)
482 val sent_oldest_first : unit -> Jmap.Methods.Comparator.t
483
484 (** Sort by subject (A-Z) *)
485 val subject_asc : unit -> Jmap.Methods.Comparator.t
486
487 (** Sort by subject (Z-A) *)
488 val subject_desc : unit -> Jmap.Methods.Comparator.t
489
490 (** Sort by size (largest first) *)
491 val size_largest_first : unit -> Jmap.Methods.Comparator.t
492
493 (** Sort by size (smallest first) *)
494 val size_smallest_first : unit -> Jmap.Methods.Comparator.t
495
496 (** Sort by from address (A-Z) *)
497 val from_asc : unit -> Jmap.Methods.Comparator.t
498
499 (** Sort by from address (Z-A) *)
500 val from_desc : unit -> Jmap.Methods.Comparator.t
501end
502
503(** High-level email operations are implemented in the Jmap.Unix.Email module *)