My agentic slop goes here. Not intended for anyone else!
1(** Fastmail Example using high-level JMAP client API
2
3 This example demonstrates the new JMAP client API inspired by the Rust
4 jmap-client library. It shows how to connect to Fastmail and fetch recent
5 emails using the simplified high-level interface.
6
7 Key improvements over manual JSON construction:
8 - Single-line operations for common tasks
9 - Automatic result reference handling
10 - Built-in error handling and resource management
11 - Rich error context for debugging *)
12
13open Printf
14
15let (let*) = Result.bind
16
17let show_error = function
18 | `Network_error (kind, msg, retryable) ->
19 let retry_hint = if retryable then " (retryable)" else " (not retryable)" in
20 printf "Network Error%s: %s\n" retry_hint msg
21 | `Auth_error (kind, msg) ->
22 printf "Authentication Error: %s\n" msg
23 | `Parse_error (kind, context) ->
24 printf "Parse Error: %s\n" context
25 | error ->
26 printf "Error: %s\n" (Jmap.Error.Utils.context error)
27let main () =
28 (* Initialize crypto for TLS *)
29 Mirage_crypto_rng_unix.use_default ();
30
31 Eio_main.run @@ fun env ->
32
33 printf "JMAP Client Example - Fastmail\n";
34 printf "===============================\n\n";
35
36 (* Read API credentials *)
37 let api_key =
38 try
39 let ic = open_in ".api-key" in
40 let key = String.trim (input_line ic) in
41 close_in ic; key
42 with
43 | Sys_error _ -> failwith "Please create .api-key file with your Fastmail API token"
44 in
45
46 printf "Loaded API credentials\n";
47
48 (* Connect to server using high-level client *)
49 let* client = Jmap_unix.Client.connect
50 ~credentials:(`Bearer api_key)
51 env "https://api.fastmail.com" in
52
53 printf "Connected to Fastmail JMAP server\n";
54 printf "Account: %s\n\n" (Jmap_unix.Client.primary_account client);
55
56 (* Query recent emails with filtering *)
57 let* emails = Jmap_unix.Client.query_emails client
58 ~filter:(Jmap_email.Query.Filter.has_keyword "$draft" |> Jmap_email.Query.Filter.negate)
59 ~sort:[Jmap_email.Query.Sort.by_date_desc]
60 ~limit:5
61 ~properties:[`Id; `ThreadId; `From; `Subject; `ReceivedAt; `Preview; `Keywords]
62 () in
63
64 printf "Found %d recent emails:\n\n" (List.length emails);
65
66 (* Display emails *)
67 List.iteri (fun i email ->
68 printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
69 printf "Email #%d:\n" (i + 1);
70 printf " Subject: %s\n" (Jmap_email.Email.subject email |> Option.value ~default:"(No Subject)");
71
72 (* Show sender *)
73 (match Jmap_email.Email.from email with
74 | Some (sender :: _) ->
75 let name = Jmap_email.Address.name sender |> Option.value ~default:"" in
76 let email_addr = Jmap_email.Address.email sender in
77 printf " From: %s <%s>\n" name email_addr
78 | _ -> printf " From: (Unknown)\n");
79
80 (* Show received date *)
81 (match Jmap_email.Email.received_at email with
82 | Some timestamp ->
83 let date_str = Jmap.Types.Date.of_timestamp timestamp |> Jmap.Types.Date.to_rfc3339 in
84 printf " Date: %s\n" date_str
85 | None -> ());
86
87 (* Show preview if available *)
88 (match Jmap_email.Email.preview email with
89 | Some preview when String.length preview > 0 ->
90 let preview_str = if String.length preview > 100 then
91 String.sub preview 0 97 ^ "..." else preview in
92 printf " Preview: %s\n" preview_str
93 | _ -> ());
94 ) emails;
95
96 printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
97
98 (* Show connection statistics *)
99 let stats = Jmap_unix.Client.stats client in
100 printf "Connection Statistics:\n";
101 printf " • Requests sent: %d (successful: %d, failed: %d)\n"
102 stats.requests_sent stats.requests_successful stats.requests_failed;
103 printf " • Data transferred: %Ld bytes sent, %Ld bytes received\n"
104 stats.bytes_sent stats.bytes_received;
105 printf " • Average response time: %.2f ms\n" (stats.average_response_time *. 1000.0);
106
107 (* Cleanup *)
108 Jmap_unix.Client.close client;
109 printf "Client closed and resources cleaned up\n";
110
111 Ok ()
112
113let () =
114 match main () with
115 | Ok () ->
116 printf "\nExample completed successfully\n";
117 exit 0
118 | Error error ->
119 printf "\n";
120 show_error error;
121 printf "\nCheck error details above for troubleshooting\n";
122 exit 1