···11open Printf
2233+(* Result monad operator for cleaner error handling *)
44+let (let+) x f = Result.bind x f
55+36let fetch_recent_emails env ctx session =
47 try
58 let account_id = Jmap_unix.Session_utils.get_primary_mail_account session in
69 printf "Using account: %s\n" account_id;
1010+ printf "Building JMAP request using library functions...\n";
711812 (* Create sort comparator using proper JSON generation *)
913 let sort_comparator = Jmap.Methods.Comparator.v
···1115 ~is_ascending:false
1216 () in
13171414- (* Try using the manual JMAP request approach directly *)
1515- printf "Using manual JMAP request approach...\n";
1616-1718 (* Build Email/query request using Jmap.Methods functions *)
1819 let builder = Jmap_unix.build ctx in
1919- let builder = Jmap_unix.using builder ["urn:ietf:params:jmap:core"; "urn:ietf:params:jmap:mail"] in
2020+ let builder = Jmap_unix.using builder [Jmap.Protocol.capability_core; Jmap.Protocol.capability_mail] in
20212122 (* Create Email/query arguments without position parameter *)
2223 let query_args = Jmap.Methods.Query_args.v
···2930 let builder = Jmap_unix.add_method_call builder "Email/query" query_json "q1" in
30313132 (* Add Email/get to fetch details using the query results *)
3232- (* Using manual result reference construction since library version has issues *)
3333- let get_json = `Assoc [
3434- ("accountId", `String account_id);
3535- ("#ids", `Assoc [
3636- ("resultOf", `String "q1");
3737- ("name", `String "Email/query");
3838- ("path", `String "/ids")
3939- ]);
4040- ("properties", `List [
4141- `String "id";
4242- `String "subject";
4343- `String "from";
4444- `String "receivedAt";
4545- `String "preview"
4646- ])
4747- ] in
4848-3333+ let get_args = Jmap.Methods.Get_args.v
3434+ ~account_id
3535+ ~properties:["id"; "subject"; "from"; "receivedAt"; "preview"]
3636+ () in
3737+ let (get_args_with_ref, result_ref_json) = Jmap.Methods.Get_args.with_result_reference
3838+ get_args
3939+ ~result_of:"q1"
4040+ ~name:"Email/query"
4141+ ~path:"/ids"
4242+ in
4343+ let get_json = Jmap.Methods.Get_args.to_json ~result_reference_ids:(Some result_ref_json) get_args_with_ref in
4944 let builder = Jmap_unix.add_method_call builder "Email/get" get_json "g1" in
50455146 (* Execute the request *)
5252- match Jmap_unix.execute env builder with
5353- | Ok response ->
5454- printf "✓ Got JMAP response\n";
5555-5656- (* Parse the query response using the library function *)
5757- (match Jmap_unix.Response.extract_method ~method_name:"Email/query" ~method_call_id:"q1" response with
5858- | Ok query_response_json ->
5959- (match Jmap.Methods.Query_response.of_json query_response_json with
6060- | Ok query_response ->
6161- let ids = Jmap.Methods.Query_response.ids query_response in
6262- printf "✓ Found %d emails\n\n" (List.length ids);
6363-6464- (* Parse the get response using the library function *)
6565- (match Jmap_unix.Response.extract_method ~method_name:"Email/get" ~method_call_id:"g1" response with
6666- | Ok get_response_json ->
6767- (* Create a wrapper for from_json since Jmap_email.of_json returns Result *)
6868- let email_from_json json =
6969- match Jmap_email.of_json json with
7070- | Ok email -> email
7171- | Error err -> failwith ("Email parse error: " ^ err)
7272- in
7373- (match Jmap.Methods.Get_response.of_json ~from_json:email_from_json get_response_json with
7474- | Ok get_response ->
7575- let emails = Jmap.Methods.Get_response.list get_response in
7676- List.iteri (fun i email ->
7777- printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
7878- printf "Email #%d:\n" (i + 1);
7979-8080- (* Use typed accessor functions instead of direct JSON parsing *)
8181- let subject = match Jmap_email.subject email with
8282- | Some s -> s
8383- | None -> "(No Subject)"
8484- in
8585- printf " Subject: %s\n" subject;
8686-8787- (* Use typed accessor for sender *)
8888- (match Jmap_email.from email with
8989- | Some from_list when from_list <> [] ->
9090- let sender = List.hd from_list in
9191- let email_addr = Jmap_email.Email_address.email sender in
9292- (match Jmap_email.Email_address.name sender with
9393- | Some name -> printf " From: %s <%s>\n" name email_addr
9494- | None -> printf " From: %s\n" email_addr)
9595- | _ -> printf " From: (Unknown)\n");
9696-9797- (* Use typed accessor for date *)
9898- (match Jmap_email.received_at email with
9999- | Some timestamp ->
100100- let date = Jmap.Date.of_timestamp timestamp in
101101- let date_str = Jmap.Date.to_rfc3339 date in
102102- printf " Date: %s\n" date_str
103103- | None -> printf " Date: (Unknown)\n");
104104-105105- (* Use typed accessor for preview *)
106106- (match Jmap_email.preview email with
107107- | Some preview when String.length preview > 0 ->
108108- let short_preview = if String.length preview > 100
109109- then (String.sub preview 0 97) ^ "..."
110110- else preview in
111111- printf " Preview: %s\n" short_preview
112112- | _ -> ())
113113- ) emails;
114114- printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
115115- Ok ()
116116- | Error parse_error ->
117117- printf "Failed to parse email get response: %s\n" (Jmap.Protocol.Error.error_to_string parse_error);
118118- Error (Jmap.Protocol.Error.protocol_error ("Email get parse error: " ^ Jmap.Protocol.Error.error_to_string parse_error)))
119119- | Error e ->
120120- printf "Failed to extract get response: %s\n" (Jmap.Protocol.Error.error_to_string e);
121121- Error e)
122122- | Error parse_error ->
123123- printf "Failed to parse query response: %s\n" (Jmap.Protocol.Error.error_to_string parse_error);
124124- Error (Jmap.Protocol.Error.protocol_error ("Query parse error: " ^ Jmap.Protocol.Error.error_to_string parse_error)))
125125- | Error e ->
126126- printf "Failed to extract query results: %s\n" (Jmap.Protocol.Error.error_to_string e);
127127- Error e)
128128- | Error e ->
129129- printf "JMAP request failed: %s\n" (Jmap.Protocol.Error.error_to_string e);
130130- Error e
4747+ let+ response = Jmap_unix.execute env builder in
4848+ printf "✓ Got JMAP response\n";
4949+5050+ let+ query_response_json = Jmap_unix.Response.extract_method ~method_name:"Email/query" ~method_call_id:"q1" response in
5151+ let+ query_response = Jmap.Methods.Query_response.of_json query_response_json in
5252+ let ids = Jmap.Methods.Query_response.ids query_response in
5353+ printf "✓ Found %d emails\n\n" (List.length ids);
5454+5555+ let+ get_response_json = Jmap_unix.Response.extract_method ~method_name:"Email/get" ~method_call_id:"g1" response in
5656+ (* Create a wrapper for from_json since Jmap_email.of_json returns Result *)
5757+ let email_from_json json =
5858+ match Jmap_email.of_json json with
5959+ | Ok email -> email
6060+ | Error err -> failwith ("Email parse error: " ^ err)
6161+ in
6262+ let+ get_response = Jmap.Methods.Get_response.of_json ~from_json:email_from_json get_response_json in
6363+ let emails = Jmap.Methods.Get_response.list get_response in
6464+6565+ List.iteri (fun i email ->
6666+ printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
6767+ printf "Email #%d:\n" (i + 1);
6868+6969+ let subject = match Jmap_email.subject email with
7070+ | Some s -> s
7171+ | None -> "(No Subject)"
7272+ in
7373+ printf " Subject: %s\n" subject;
7474+7575+ (match Jmap_email.from email with
7676+ | Some from_list when from_list <> [] ->
7777+ let sender = List.hd from_list in
7878+ let email_addr = Jmap_email.Email_address.email sender in
7979+ (match Jmap_email.Email_address.name sender with
8080+ | Some name -> printf " From: %s <%s>\n" name email_addr
8181+ | None -> printf " From: %s\n" email_addr)
8282+ | _ -> printf " From: (Unknown)\n");
8383+8484+ (match Jmap_email.received_at email with
8585+ | Some timestamp ->
8686+ let date = Jmap.Date.of_timestamp timestamp in
8787+ let date_str = Jmap.Date.to_rfc3339 date in
8888+ printf " Date: %s\n" date_str
8989+ | None -> printf " Date: (Unknown)\n");
9090+9191+ (match Jmap_email.preview email with
9292+ | Some preview when String.length preview > 0 ->
9393+ let short_preview = if String.length preview > 100
9494+ then (String.sub preview 0 97) ^ "..."
9595+ else preview in
9696+ printf " Preview: %s\n" short_preview
9797+ | _ -> ())
9898+ ) emails;
9999+ printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
100100+ Ok ()
131101 with
132102 | exn -> Error (Jmap.Protocol.Error.protocol_error ("Exception: " ^ Printexc.to_string exn))
133103
+6-6
jmap/jmap-unix/jmap_unix.ml
···244244245245let build ctx = {
246246 ctx;
247247- using = ["urn:ietf:params:jmap:core"];
247247+ using = [Jmap.Protocol.capability_core];
248248 method_calls = [];
249249}
250250···606606 | None -> `Null);
607607 ] in
608608 let builder = build ctx
609609- |> fun b -> using b ["urn:ietf:params:jmap:core"; "urn:ietf:params:jmap:mail"]
609609+ |> fun b -> using b [Jmap.Protocol.capability_core; Jmap.Protocol.capability_mail]
610610 |> fun b -> add_method_call b "Email/get" args "get-1"
611611 in
612612 match execute env builder with
···632632 ("position", match position with Some p -> `Int p | None -> `Null);
633633 ] in
634634 let builder = build ctx
635635- |> fun b -> using b ["urn:ietf:params:jmap:core"; "urn:ietf:params:jmap:mail"]
635635+ |> fun b -> using b [Jmap.Protocol.capability_core; Jmap.Protocol.capability_mail]
636636 |> fun b -> add_method_call b "Email/query" args "query-1"
637637 in
638638 match execute env builder with
···656656 ) email_ids));
657657 ] in
658658 let builder = build ctx
659659- |> fun b -> using b ["urn:ietf:params:jmap:core"; "urn:ietf:params:jmap:mail"]
659659+ |> fun b -> using b [Jmap.Protocol.capability_core; Jmap.Protocol.capability_mail]
660660 |> fun b -> add_method_call b "Email/set" args "set-1"
661661 in
662662 match execute env builder with
···691691 | None -> `Null);
692692 ] in
693693 let builder = build ctx
694694- |> fun b -> using b ["urn:ietf:params:jmap:core"; "urn:ietf:params:jmap:mail"]
694694+ |> fun b -> using b [Jmap.Protocol.capability_core; Jmap.Protocol.capability_mail]
695695 |> fun b -> add_method_call b "Email/import" args "import-1"
696696 in
697697 match execute env builder with
···758758 let open Jmap.Protocol.Session.Session in
759759 let primary_accs = primary_accounts session in
760760 try
761761- Hashtbl.find primary_accs "urn:ietf:params:jmap:mail"
761761+ Hashtbl.find primary_accs Jmap.Protocol.capability_mail
762762 with
763763 | Not_found ->
764764 let accounts = accounts session in
+1-1
jmap/jmap/jmap_methods.ml
···2929 ("accountId", `String t.account_id);
3030 ] in
3131 let fields = match result_reference_ids with
3232- | Some ref_json -> ("ids", ref_json) :: base_fields
3232+ | Some ref_json -> ("#ids", ref_json) :: base_fields
3333 | None ->
3434 match t.ids with
3535 | Some id_list -> ("ids", (`List (List.map (fun id -> `String id) id_list) : Yojson.Safe.t)) :: base_fields