this repo has no description
1(*---------------------------------------------------------------------------
2 Copyright (c) 2025 Anil Madhavapeddy. All rights reserved.
3 SPDX-License-Identifier: ISC
4 ---------------------------------------------------------------------------*)
5
6(** JMAP test client - connects to a JMAP server and queries recent emails *)
7
8let () =
9 (* Parse command line arguments *)
10 let usage = "Usage: jmap-test <session-url> <api-key>" in
11 let args = ref [] in
12 Arg.parse [] (fun arg -> args := arg :: !args) usage;
13 let session_url, api_key =
14 match List.rev !args with
15 | [url; key] -> (url, key)
16 | _ ->
17 prerr_endline usage;
18 exit 1
19 in
20
21 (* Run with Eio *)
22 Eio_main.run @@ fun env ->
23 Eio.Switch.run @@ fun sw ->
24
25 (* Create HTTP client with Bearer token auth *)
26 let requests = Requests.create ~sw env in
27 let auth = Requests.Auth.bearer ~token:api_key in
28
29 Printf.printf "Connecting to %s...\n%!" session_url;
30
31 (* Create JMAP client from session URL *)
32 match Jmap_eio.Client.create_from_url ~auth requests session_url with
33 | Error e ->
34 Printf.eprintf "Failed to connect: %s\n" (Jmap_eio.Client.error_to_string e);
35 exit 1
36 | Ok client ->
37 let session = Jmap_eio.Client.session client in
38 Printf.printf "Connected! Username: %s\n%!" (Jmap_proto.Session.username session);
39
40 (* Get primary mail account *)
41 let primary_account_id =
42 match Jmap_proto.Session.primary_account_for Jmap_proto.Capability.mail session with
43 | Some id -> id
44 | None ->
45 prerr_endline "No primary mail account found";
46 exit 1
47 in
48 Printf.printf "Primary mail account: %s\n%!" (Jmap_proto.Id.to_string primary_account_id);
49
50 (* Query for recent emails - get the 10 most recent *)
51 let sort = [Jmap_proto.Filter.comparator ~is_ascending:false "receivedAt"] in
52 let query_inv = Jmap_eio.Client.Build.email_query
53 ~call_id:"q1"
54 ~account_id:primary_account_id
55 ~sort
56 ~limit:10L
57 ()
58 in
59
60 (* Build request with mail capability *)
61 let req = Jmap_eio.Client.Build.make_request
62 ~capabilities:[Jmap_proto.Capability.core; Jmap_proto.Capability.mail]
63 [query_inv]
64 in
65
66 Printf.printf "Querying recent emails...\n%!";
67
68 match Jmap_eio.Client.request client req with
69 | Error e ->
70 Printf.eprintf "Query failed: %s\n" (Jmap_eio.Client.error_to_string e);
71 exit 1
72 | Ok response ->
73 (* Parse the query response *)
74 match Jmap_eio.Client.Parse.parse_email_query ~call_id:"q1" response with
75 | Error e ->
76 Printf.eprintf "Failed to parse query response: %s\n" (Jsont.Error.to_string e);
77 exit 1
78 | Ok query_result ->
79 let email_ids = query_result.ids in
80 Printf.printf "Found %d emails\n%!" (List.length email_ids);
81
82 if List.length email_ids = 0 then (
83 Printf.printf "No emails found.\n%!";
84 ) else (
85 (* Fetch the email details *)
86 let get_inv = Jmap_eio.Client.Build.email_get
87 ~call_id:"g1"
88 ~account_id:primary_account_id
89 ~ids:email_ids
90 ~properties:["id"; "subject"; "from"; "receivedAt"; "preview"]
91 ()
92 in
93
94 let req2 = Jmap_eio.Client.Build.make_request
95 ~capabilities:[Jmap_proto.Capability.core; Jmap_proto.Capability.mail]
96 [get_inv]
97 in
98
99 Printf.printf "Fetching email details...\n%!";
100
101 match Jmap_eio.Client.request client req2 with
102 | Error e ->
103 Printf.eprintf "Get failed: %s\n" (Jmap_eio.Client.error_to_string e);
104 exit 1
105 | Ok response2 ->
106 match Jmap_eio.Client.Parse.parse_email_get ~call_id:"g1" response2 with
107 | Error e ->
108 Printf.eprintf "Failed to parse get response: %s\n" (Jsont.Error.to_string e);
109 exit 1
110 | Ok get_result ->
111 Printf.printf "\n=== Recent Emails ===\n\n%!";
112 List.iter (fun email ->
113 let id = Jmap_proto.Id.to_string (Jmap_mail.Email.id email) in
114 let subject = Option.value (Jmap_mail.Email.subject email) ~default:"(no subject)" in
115 let from_addrs = Option.value (Jmap_mail.Email.from email) ~default:[] in
116 let from_str = match from_addrs with
117 | [] -> "(unknown sender)"
118 | addr :: _ ->
119 let name = Option.value (Jmap_mail.Email_address.name addr) ~default:"" in
120 let email_addr = Jmap_mail.Email_address.email addr in
121 if name = "" then email_addr
122 else Printf.sprintf "%s <%s>" name email_addr
123 in
124 let received =
125 Jmap_proto.Date.Utc.to_string (Jmap_mail.Email.received_at email)
126 in
127 let preview = Jmap_mail.Email.preview email in
128 let preview_short =
129 if String.length preview > 80 then
130 String.sub preview 0 77 ^ "..."
131 else preview
132 in
133 Printf.printf "ID: %s\n" id;
134 Printf.printf "From: %s\n" from_str;
135 Printf.printf "Date: %s\n" received;
136 Printf.printf "Subject: %s\n" subject;
137 Printf.printf "Preview: %s\n" preview_short;
138 Printf.printf "\n%!";
139 ) get_result.list;
140 Printf.printf "=== End of emails ===\n%!"
141 )