(** High-level JMAP Client API. This module provides a high-level JMAP client API inspired by the Rust jmap-client library. Features include automatic result reference chaining, comprehensive error handling, and fluent method calls. Key features: - Automatic method chaining with result references (no manual call IDs) - Comprehensive error handling with detailed context and retry hints - Fluent builder patterns for complex queries and operations - High-level methods that eliminate manual JSON construction - Production-ready with connection management and resource cleanup {b Usage example}: {[ let* client = Client.connect ~credentials env "https://jmap.example.org" in let* emails = Client.query_emails client ~filter:(Filter.in_mailbox inbox_id) ~limit:5 in let* mailbox_id = Client.create_mailbox client ~account_id ~name:"Test" () in Client.destroy_email client ~account_id ~email_id ]} *) (** {1 Client Lifecycle} *) (** JMAP client with automatic resource management *) type t (** Enhanced authentication methods *) type credentials = [ | `Basic of string * string (** Basic auth with username and password *) | `Bearer of string (** Bearer token auth *) | `Custom of string * string (** Custom header name and value *) | `Session_cookie of string * string (** Session cookie name and value *) ] (** Advanced client configuration *) type config = { connect_timeout : float option; (** Connection timeout in seconds (default: 10.0) *) request_timeout : float option; (** Request timeout in seconds (default: 30.0) *) max_concurrent_requests : int option; (** Maximum concurrent requests (default: 10) *) max_request_size : int option; (** Maximum request size in bytes (default: 10MB) *) user_agent : string option; (** User-Agent header value *) retry_attempts : int option; (** Number of automatic retries (default: 3) *) retry_delay : float option; (** Base delay between retries in seconds (default: 1.0) *) enable_push : bool; (** Enable push notifications (default: false) *) } (** Create default client configuration *) val default_config : unit -> config (** Connect to JMAP server. This single function handles: - Session discovery via .well-known/jmap - Authentication and capability negotiation - Connection pooling and resource setup - Error handling with detailed diagnostics @param credentials Authentication method @param env Eio environment for network operations @param url Base server URL (will auto-discover JMAP endpoint) @param config Optional configuration (uses defaults if not provided) @return Connected client ready for operations *) val connect : credentials:credentials -> ?config:config -> < net : 'a Eio.Net.t ; .. > -> string -> (t, Jmap.Error.error) result (** Get the primary account ID for mail operations. Most clients only need this for email, mailbox, and thread operations. *) val primary_account : t -> string (** Get account ID for specific capability. @param capability JMAP capability URI (e.g., "urn:ietf:params:jmap:mail") @return Account ID supporting that capability, or None if not available *) val account_for_capability : t -> string -> string option (** Check if server supports a specific capability *) val has_capability : t -> string -> bool (** Get server capabilities and limits *) val capabilities : t -> (string * Yojson.Safe.t) list (** Close client and cleanup all resources *) val close : t -> unit (** {1 Email Operations} *) (** High-level email query with automatic result chaining. Combines Email/query and Email/get into single operation with automatic result reference handling. No manual JSON construction required. @param client Connected JMAP client @param account_id Account to query (uses primary_account if not specified) @param filter Email filter conditions (optional) @param sort Sort criteria list (optional, defaults to date descending) @param limit Maximum results to return (optional, defaults to 20) @param properties Email properties to fetch (optional, uses smart defaults) @return List of email objects matching criteria *) val query_emails : t -> ?account_id:string -> ?filter:Jmap_email.Query.Filter.t -> ?sort:Jmap_email.Query.Sort.t list -> ?limit:int -> ?properties:Jmap_email.Property.t list -> unit -> (Jmap_email.Email.t list, Jmap.Error.error) result (** Get specific emails by ID with property selection. @param client Connected JMAP client @param account_id Account containing the emails @param ids List of email IDs to fetch @param properties Properties to include (optional, uses smart defaults) @return List of email objects (may be fewer than requested if some IDs don't exist) *) val get_emails : t -> ?account_id:string -> string list -> ?properties:Jmap_email.Property.t list -> unit -> (Jmap_email.Email.t list, Jmap.Error.error) result (** Import raw email message into mailboxes. @param client Connected JMAP client @param account_id Target account @param raw_message Complete RFC 5322 message as bytes @param mailbox_ids List of mailboxes to place the message in @param keywords Initial keywords/flags (optional) @param received_at Override received timestamp (optional, uses current time) @return Imported email object *) val import_email : t -> account_id:string -> raw_message:bytes -> mailbox_ids:string list -> ?keywords:string list -> ?received_at:Jmap.Types.date -> unit -> (Jmap_email.Email.t, Jmap.Error.error) result (** Destroy email by ID. @param client Connected JMAP client @param account_id Account containing the email @param email_id Email to destroy @return Success unit or detailed error *) val destroy_email : t -> account_id:string -> email_id:string -> (unit, Jmap.Error.error) result (** Set email keywords (flags) - replaces all existing keywords. @param client Connected JMAP client @param account_id Account containing the email @param email_id Email to modify @param keywords New keyword list (e.g., ["$seen"; "$flagged"]) @return Success unit or detailed error *) val set_email_keywords : t -> account_id:string -> email_id:string -> keywords:string list -> (unit, Jmap.Error.error) result (** Set email mailboxes - replaces all existing mailbox assignments. @param client Connected JMAP client @param account_id Account containing the email @param email_id Email to modify @param mailbox_ids New mailbox list @return Success unit or detailed error *) val set_email_mailboxes : t -> account_id:string -> email_id:string -> mailbox_ids:string list -> (unit, Jmap.Error.error) result (** {1 Mailbox Operations} *) (** Query mailboxes with filtering and sorting. @param client Connected JMAP client @param account_id Account to query @param filter Mailbox filter conditions (optional) @param sort Sort criteria (optional, defaults to name ascending) @return List of mailbox objects *) val query_mailboxes : t -> ?account_id:string -> ?filter:Jmap_email.Mailbox.Filter.t -> ?sort:Jmap_email.Mailbox.Sort.t list -> unit -> (Jmap_email.Mailbox.t list, Jmap.Error.error) result (** Create new mailbox. @param client Connected JMAP client @param account_id Target account @param name Mailbox name (human-readable) @param parent_id Parent mailbox ID for hierarchy (optional) @param role Special mailbox role (optional, e.g., Inbox, Sent) @return ID of newly created mailbox *) val create_mailbox : t -> account_id:string -> name:string -> ?parent_id:string -> ?role:Jmap_email.Mailbox.Role.t -> unit -> (string, Jmap.Error.error) result (** Destroy mailbox. @param client Connected JMAP client @param account_id Account containing mailbox @param mailbox_id Mailbox to destroy @param on_destroy_remove_emails If true, delete contained emails; if false, move to Trash (default: false) @return Success unit or detailed error *) val destroy_mailbox : t -> account_id:string -> mailbox_id:string -> ?on_destroy_remove_emails:bool -> unit -> (unit, Jmap.Error.error) result (** {1 Advanced Features} *) (** Batch request builder for multiple operations with automatic result chaining. This provides the foundation for complex multi-method operations while maintaining the automatic result reference system. {b Usage example}: {[ let batch = Client.batch client in let query_ref = Batch.query_emails batch ~filter ~limit:10 in let get_ref = Batch.get_emails_ref batch query_ref ~properties in let* (emails, _) = Batch.execute batch in process_emails emails ]} *) module Batch : sig type batch_builder type 'a batch_operation (** Create new batch request builder *) val create : t -> batch_builder (** Add email query to batch with automatic result reference *) val query_emails : batch_builder -> ?account_id:string -> ?filter:Jmap_email.Query.Filter.t -> ?sort:Jmap_email.Query.Sort.t list -> ?limit:int -> unit -> string list batch_operation (** Add email get operation using result reference from query *) val get_emails_ref : batch_builder -> string list batch_operation -> ?properties:Jmap_email.Property.t list -> unit -> Jmap_email.Email.t list batch_operation (** Execute batch request and return results *) val execute : batch_builder -> (unit, Jmap.Error.error) result (** Extract results from completed operations *) val result : 'a batch_operation -> ('a, Jmap.Error.error) result end (** {1 Connection and Resource Management} *) (** Connection statistics for monitoring *) type connection_stats = { requests_sent : int; requests_successful : int; requests_failed : int; bytes_sent : int64; bytes_received : int64; connection_reuses : int; average_response_time : float; } (** Get connection statistics for monitoring *) val stats : t -> connection_stats (** Test connection health *) val ping : t -> (unit, Jmap.Error.error) result (** Force connection refresh (useful after network changes) *) val refresh_connection : t -> (unit, Jmap.Error.error) result