this repo has no description
at if-only 17 kB view raw
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 *)