This repository has no description
0

Configure Feed

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

at main 13 kB View raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(** Unified JMAP interface for OCaml 7 8 This module provides a clean, ergonomic API for working with JMAP 9 (RFC 8620/8621), combining the protocol and mail layers with abstract 10 types and polymorphic variants. 11 12 {2 Quick Start} 13 14 {[ 15 open Jmap 16 17 (* Keywords use polymorphic variants *) 18 let is_unread email = 19 not (List.mem `Seen (Email.keywords email)) 20 21 (* Mailbox roles are also polymorphic *) 22 let find_inbox mailboxes = 23 List.find_opt (fun m -> Mailbox.role m = Some `Inbox) mailboxes 24 ]} 25 26 {2 Module Structure} 27 28 - {!Proto} - Low-level protocol and mail types (RFC 8620/8621) 29 - {!module-Error}, {!Id}, {!Keyword}, {!Role}, {!Capability} - Core types 30 - {!Session}, {!Email}, {!Mailbox}, etc. - Abstract type accessors 31*) 32 33(** {1 Protocol Layer Re-exports} *) 34 35(** Low-level JMAP protocol types (RFC 8620/8621). 36 37 These are the raw protocol and mail types. For most use cases, prefer the 38 higher-level types in this module. *) 39module Proto = Jmap_proto 40 41(** {1 Core Types} *) 42 43(** Unified error type for JMAP operations. *) 44module Error : sig 45 (** Request-level error (RFC 7807 Problem Details). *) 46 type request = { 47 type_ : string; 48 status : int option; 49 title : string option; 50 detail : string option; 51 limit : string option; 52 } 53 54 (** Method-level error. *) 55 type method_ = { 56 type_ : string; 57 description : string option; 58 } 59 60 (** Set operation error for a specific object. *) 61 type set = { 62 type_ : string; 63 description : string option; 64 properties : string list option; 65 } 66 67 (** Unified error type. 68 69 All errors from JSON parsing, HTTP, session management, and JMAP method 70 calls are represented as polymorphic variants. *) 71 type t = [ 72 | `Request of request 73 | `Method of method_ 74 | `Set of string * set 75 | `Json of string 76 | `Http of int * string 77 | `Connection of string 78 | `Session of string 79 ] 80 81 val pp : Format.formatter -> t -> unit 82 val to_string : t -> string 83end 84 85(** JMAP identifier type. *) 86module Id : sig 87 type t 88 89 val of_string : string -> (t, string) result 90 val of_string_exn : string -> t 91 val to_string : t -> string 92 val compare : t -> t -> int 93 val equal : t -> t -> bool 94 val pp : Format.formatter -> t -> unit 95end 96 97(** Email keyword type. 98 99 Standard keywords are represented as polymorphic variants. 100 Custom keywords use [`Custom of string]. *) 101module Keyword : sig 102 (** RFC 8621 standard keywords *) 103 type standard = [ 104 | `Seen 105 | `Flagged 106 | `Answered 107 | `Draft 108 | `Forwarded 109 | `Phishing 110 | `Junk 111 | `NotJunk 112 ] 113 114 (** draft-ietf-mailmaint extended keywords *) 115 type extended = [ 116 | `Notify 117 | `Muted 118 | `Followed 119 | `Memo 120 | `HasMemo 121 | `HasAttachment 122 | `HasNoAttachment 123 | `AutoSent 124 | `Unsubscribed 125 | `CanUnsubscribe 126 | `Imported 127 | `IsTrusted 128 | `MaskedEmail 129 | `New 130 ] 131 132 (** Apple Mail flag color keywords *) 133 type flag_bits = [ 134 | `MailFlagBit0 135 | `MailFlagBit1 136 | `MailFlagBit2 137 ] 138 139 type t = [ 140 | standard 141 | extended 142 | flag_bits 143 | `Custom of string 144 ] 145 146 val of_string : string -> t 147 val to_string : t -> string 148 val pp : Format.formatter -> t -> unit 149 150 (** Apple Mail flag colors *) 151 type flag_color = [ 152 | `Red 153 | `Orange 154 | `Yellow 155 | `Green 156 | `Blue 157 | `Purple 158 | `Gray 159 ] 160 161 val flag_color_of_keywords : t list -> flag_color option 162 (** [flag_color_of_keywords keywords] extracts the flag color from a list 163 of keywords. Returns [None] for invalid bit combinations. *) 164 165 val flag_color_to_keywords : flag_color -> t list 166 (** [flag_color_to_keywords color] returns the keywords to set for the color. *) 167end 168 169(** Mailbox role type. 170 171 Standard roles are represented as polymorphic variants. 172 Custom roles use [`Custom of string]. *) 173module Role : sig 174 (** RFC 8621 standard roles *) 175 type standard = [ 176 | `Inbox 177 | `Sent 178 | `Drafts 179 | `Trash 180 | `Junk 181 | `Archive 182 | `Flagged 183 | `Important 184 | `All 185 | `Subscribed 186 ] 187 188 (** draft-ietf-mailmaint extended roles *) 189 type extended = [ 190 | `Snoozed 191 | `Scheduled 192 | `Memos 193 ] 194 195 type t = [ 196 | standard 197 | extended 198 | `Custom of string 199 ] 200 201 val of_string : string -> t 202 val to_string : t -> string 203 val pp : Format.formatter -> t -> unit 204end 205 206(** JMAP capability type. 207 208 Standard capabilities are represented as polymorphic variants. 209 Custom capabilities use [`Custom of string]. *) 210module Capability : sig 211 type t = [ 212 | `Core 213 | `Mail 214 | `Submission 215 | `VacationResponse 216 | `Custom of string 217 ] 218 219 val core_uri : string 220 val mail_uri : string 221 val submission_uri : string 222 val vacation_uri : string 223 224 val of_string : string -> t 225 val to_string : t -> string 226 val pp : Format.formatter -> t -> unit 227end 228 229(** {1 Session Types} *) 230 231(** JMAP session information. *) 232module Session : sig 233 (** Account information. *) 234 module Account : sig 235 type t 236 237 val name : t -> string 238 val is_personal : t -> bool 239 val is_read_only : t -> bool 240 end 241 242 type t 243 244 val capabilities : t -> (string * Jsont.json) list 245 val accounts : t -> (Id.t * Account.t) list 246 val primary_accounts : t -> (string * Id.t) list 247 val username : t -> string 248 val api_url : t -> string 249 val download_url : t -> string 250 val upload_url : t -> string 251 val event_source_url : t -> string 252 val state : t -> string 253 254 val get_account : Id.t -> t -> Account.t option 255 val primary_account_for : string -> t -> Id.t option 256 val has_capability : string -> t -> bool 257end 258 259(** {1 Mail Types} *) 260 261(** Email address with optional display name. *) 262module Email_address : sig 263 type t 264 265 val name : t -> string option 266 val email : t -> string 267 val create : ?name:string -> string -> t 268end 269 270(** Email mailbox. 271 All accessors return option types since responses only include requested properties. *) 272module Mailbox : sig 273 type t 274 275 val id : t -> Id.t option 276 val name : t -> string option 277 val parent_id : t -> Id.t option 278 val sort_order : t -> int64 option 279 val total_emails : t -> int64 option 280 val unread_emails : t -> int64 option 281 val total_threads : t -> int64 option 282 val unread_threads : t -> int64 option 283 val is_subscribed : t -> bool option 284 val role : t -> Role.t option 285 286 (** Mailbox rights. *) 287 module Rights : sig 288 type t 289 290 val may_read_items : t -> bool 291 val may_add_items : t -> bool 292 val may_remove_items : t -> bool 293 val may_set_seen : t -> bool 294 val may_set_keywords : t -> bool 295 val may_create_child : t -> bool 296 val may_rename : t -> bool 297 val may_delete : t -> bool 298 val may_submit : t -> bool 299 end 300 301 val my_rights : t -> Rights.t option 302end 303 304(** Email thread. 305 All accessors return option types since responses only include requested properties. *) 306module Thread : sig 307 type t 308 309 val id : t -> Id.t option 310 val email_ids : t -> Id.t list option 311end 312 313(** Email message. *) 314module Email : sig 315 (** Email body part. *) 316 module Body : sig 317 type part 318 type value 319 320 val part_id : part -> string option 321 val blob_id : part -> Id.t option 322 val size : part -> int64 option 323 val name : part -> string option 324 val type_ : part -> string 325 val charset : part -> string option 326 val disposition : part -> string option 327 val cid : part -> string option 328 val language : part -> string list option 329 val location : part -> string option 330 331 val value_text : value -> string 332 val value_is_truncated : value -> bool 333 val value_is_encoding_problem : value -> bool 334 end 335 336 (** All accessors return option types since responses only include requested properties. *) 337 type t 338 339 val id : t -> Id.t option 340 val blob_id : t -> Id.t option 341 val thread_id : t -> Id.t option 342 val mailbox_ids : t -> (Id.t * bool) list option 343 val size : t -> int64 option 344 val received_at : t -> Ptime.t option 345 val message_id : t -> string list option 346 val in_reply_to : t -> string list option 347 val references : t -> string list option 348 val subject : t -> string option 349 val sent_at : t -> Ptime.t option 350 val has_attachment : t -> bool option 351 val preview : t -> string option 352 353 (** Get active keywords as polymorphic variants. 354 Returns empty list if keywords property was not requested. *) 355 val keywords : t -> Keyword.t list 356 357 (** Check if email has a specific keyword. 358 Returns false if keywords property was not requested. *) 359 val has_keyword : Keyword.t -> t -> bool 360 361 val from : t -> Email_address.t list option 362 val to_ : t -> Email_address.t list option 363 val cc : t -> Email_address.t list option 364 val bcc : t -> Email_address.t list option 365 val reply_to : t -> Email_address.t list option 366 val sender : t -> Email_address.t list option 367 368 val text_body : t -> Body.part list option 369 val html_body : t -> Body.part list option 370 val attachments : t -> Body.part list option 371 val body_values : t -> (string * Body.value) list option 372end 373 374(** Email identity for sending. 375 All accessors return option types since responses only include requested properties. *) 376module Identity : sig 377 type t 378 379 val id : t -> Id.t option 380 val name : t -> string option 381 val email : t -> string option 382 val reply_to : t -> Email_address.t list option 383 val bcc : t -> Email_address.t list option 384 val text_signature : t -> string option 385 val html_signature : t -> string option 386 val may_delete : t -> bool option 387end 388 389(** Email submission for outgoing mail. 390 All accessors return option types since responses only include requested properties. *) 391module Submission : sig 392 type t 393 394 val id : t -> Id.t option 395 val identity_id : t -> Id.t option 396 val email_id : t -> Id.t option 397 val thread_id : t -> Id.t option 398 val send_at : t -> Ptime.t option 399 val undo_status : t -> Proto.Submission.undo_status option 400 val delivery_status : t -> (string * Proto.Submission.Delivery_status.t) list option 401 val dsn_blob_ids : t -> Id.t list option 402 val mdn_blob_ids : t -> Id.t list option 403end 404 405(** Vacation auto-response. *) 406module Vacation : sig 407 type t 408 409 val id : t -> Id.t 410 val is_enabled : t -> bool 411 val from_date : t -> Ptime.t option 412 val to_date : t -> Ptime.t option 413 val subject : t -> string option 414 val text_body : t -> string option 415 val html_body : t -> string option 416end 417 418(** Search snippet with highlighted matches. *) 419module Search_snippet : sig 420 type t 421 422 val email_id : t -> Id.t 423 val subject : t -> string option 424 val preview : t -> string option 425end 426 427(** {1 Filter Types} *) 428 429(** Email filter conditions for queries. *) 430module Email_filter : sig 431 type condition 432 433 (** Create an email filter condition. 434 435 All parameters are optional. Omitted parameters are not included 436 in the filter. Use [make ()] for an empty filter. *) 437 val make : 438 ?in_mailbox:Id.t -> 439 ?in_mailbox_other_than:Id.t list -> 440 ?before:Ptime.t -> 441 ?after:Ptime.t -> 442 ?min_size:int64 -> 443 ?max_size:int64 -> 444 ?all_in_thread_have_keyword:Keyword.t -> 445 ?some_in_thread_have_keyword:Keyword.t -> 446 ?none_in_thread_have_keyword:Keyword.t -> 447 ?has_keyword:Keyword.t -> 448 ?not_keyword:Keyword.t -> 449 ?has_attachment:bool -> 450 ?text:string -> 451 ?from:string -> 452 ?to_:string -> 453 ?cc:string -> 454 ?bcc:string -> 455 ?subject:string -> 456 ?body:string -> 457 ?header:(string * string option) -> 458 unit -> condition 459end 460 461(** Mailbox filter conditions for queries. *) 462module Mailbox_filter : sig 463 type condition 464 465 (** Create a mailbox filter condition. 466 467 All parameters are optional. 468 For [role]: [Some (Some r)] filters by role [r], [Some None] filters for 469 mailboxes with no role, [None] doesn't filter by role. *) 470 val make : 471 ?parent_id:Id.t option -> 472 ?name:string -> 473 ?role:Role.t option -> 474 ?has_any_role:bool -> 475 ?is_subscribed:bool -> 476 unit -> condition 477end 478 479(** {1 Response Types} *) 480 481(** Generic /get response wrapper. *) 482module Get_response : sig 483 type 'a t 484 485 val account_id : 'a t -> Id.t 486 val state : 'a t -> string 487 val list : 'a t -> 'a list 488 val not_found : 'a t -> Id.t list 489end 490 491(** Query response. *) 492module Query_response : sig 493 type t 494 495 val account_id : t -> Id.t 496 val query_state : t -> string 497 val can_calculate_changes : t -> bool 498 val position : t -> int64 499 val ids : t -> Id.t list 500 val total : t -> int64 option 501end 502 503(** Changes response. *) 504module Changes_response : sig 505 type t 506 507 val account_id : t -> Id.t 508 val old_state : t -> string 509 val new_state : t -> string 510 val has_more_changes : t -> bool 511 val created : t -> Id.t list 512 val updated : t -> Id.t list 513 val destroyed : t -> Id.t list 514end 515 516(** {1 JSONABLE Interface} *) 517 518(** Module type for types that can be serialized to/from JSON bytes. *) 519module type JSONABLE = sig 520 type t 521 522 val of_string : string -> (t, Error.t) result 523 val to_string : t -> (string, Error.t) result 524end 525 526(** {1 Request Chaining} *) 527 528(** JMAP method chaining with automatic result references. 529 530 This module provides a monadic interface for building JMAP requests 531 where method calls can reference results from previous calls. *) 532module Chain = Chain