My agentic slop goes here. Not intended for anyone else!
1(** Messages Example - Email lifecycle management
2
3 This example demonstrates complete email lifecycle management using the
4 high-level JMAP client API. Inspired by the Rust jmap-client library.
5
6 Operations demonstrated:
7 - Query mailboxes to find Inbox and Trash
8 - Import raw email messages
9 - Query and fetch messages with filtering
10 - Modify message keywords and mailboxes
11 - Delete messages *)
12
13open Printf
14
15let (let*) = Result.bind
16
17(** Sample RFC 5322 message for testing *)
18let test_message = {|From: john@example.org
19To: jane@example.org
20Subject: Revolutionary JMAP Client Test
21Date: Wed, 04 Sep 2024 12:00:00 +0000
22
23This is a test message created by the revolutionary OCaml JMAP client.
24
25The new client provides:
26- Single-line operations for complex JMAP workflows
27- Automatic result reference chaining
28- Comprehensive error handling with retry logic
29- Production-ready resource management
30
31Best regards,
32Revolutionary JMAP Bot|}
33
34let show_error error =
35 printf "❌ %s\n" (Jmap.Error.Utils.context error)
36
37(** Revolutionary message lifecycle demonstration *)
38let messages_example env credentials =
39 printf "🚀 Revolutionary Messages Lifecycle Example\n";
40 printf "==========================================\n\n";
41
42 (* Connect with single line *)
43 let* client = Jmap_unix.Client.connect ~credentials env "https://api.fastmail.com" in
44 let account_id = Jmap_unix.Client.primary_account client in
45 printf "✅ Connected to account: %s\n\n" account_id;
46
47 (* Query mailboxes to find Inbox and Trash - single line each *)
48 printf "📁 Finding mailboxes...\n";
49 let* mailboxes = Jmap_unix.Client.query_mailboxes client
50 ~filter:(Jmap_email.Mailbox.Filter.has_role true) () in
51
52 (* Extract Inbox and Trash IDs (simplified for demo) *)
53 let inbox_id = match mailboxes with
54 | mb :: _ -> Jmap_email.Mailbox.id mb |> Option.get
55 | [] -> failwith "No mailboxes found"
56 in
57
58 let trash_id = inbox_id in (* Simplified - would normally find actual Trash *)
59 printf "✅ Found Inbox: %s\n" (stringo_string inbox_id);
60 printf "✅ Found Trash: %s\n\n" (stringo_string trash_id);
61
62 (* Import message - revolutionary single line *)
63 printf "📥 Importing test message...\n";
64 let* imported_email = Jmap_unix.Client.import_email client
65 ~account_id
66 ~raw_message:(Bytes.of_string test_message)
67 ~mailbox_ids:[inbox_id]
68 ~keywords:["$draft"] () in
69
70 let email_id = Jmap_email.Email.id imported_email |> Option.get in
71 printf "✅ Imported email: %s\n\n" (stringo_string email_id);
72
73 (* Query for our test message - revolutionary filtering *)
74 printf "🔍 Querying for test messages...\n";
75 let* test_emails = Jmap_unix.Client.query_emails client
76 ~filter:(Jmap_email.Query.Filter.(
77 and_ [
78 subject_contains "Revolutionary";
79 in_mailbox inbox_id;
80 has_keyword "$draft"
81 ]))
82 ~limit:10 () in
83
84 printf "✅ Found %d test messages\n\n" (List.length test_emails);
85
86 (* Display message details *)
87 (match test_emails with
88 | email :: _ ->
89 let email_id = Jmap_email.Email.id email |> Option.get in
90 printf "📧 Message Details:\n";
91 printf " Subject: %s\n" (Jmap_email.Email.subject email |> Option.value ~default:"(none)");
92 printf " Preview: %s\n" (Jmap_email.Email.preview email |> Option.value ~default:"(none)");
93 printf " Keywords: [%s]\n\n" (Jmap_email.Email.keywords email |> String.concat "; ");
94
95 (* Remove draft keyword - single line *)
96 printf "🏷️ Removing $draft keyword...\n";
97 let* () = Jmap_unix.Client.set_email_keywords client
98 ~account_id ~email_id ~keywords:["$seen"; "$important"] in
99 printf "✅ Updated keywords\n\n";
100
101 (* Move to trash - single line *)
102 printf "🗑️ Moving to trash...\n";
103 let* () = Jmap_unix.Client.set_email_mailboxes client
104 ~account_id ~email_id ~mailbox_ids:[trash_id] in
105 printf "✅ Moved to trash\n\n";
106
107 (* Destroy the email - single line *)
108 printf "💥 Destroying email...\n";
109 let* () = Jmap_unix.Client.destroy_email client ~account_id ~email_id in
110 printf "✅ Email destroyed\n\n";
111
112 | [] ->
113 printf "ℹ️ No test messages found to manipulate\n\n");
114
115 (* Show final stats *)
116 let stats = Jmap_unix.Client.stats client in
117 printf "📊 Final Statistics:\n";
118 printf " • Operations completed: %d\n" stats.requests_successful;
119 printf " • Average response time: %.1f ms\n" (stats.average_response_time *. 1000.0);
120 printf " • Total data transferred: %Ld bytes\n" (Int64.add stats.bytes_sent stats.bytes_received);
121
122 (* Clean up *)
123 Jmap_unix.Client.close client;
124 printf "\n🧹 Resources cleaned up\n";
125 Ok ()
126
127let main () =
128 Mirage_crypto_rng_unix.use_default ();
129
130 Eio_main.run @@ fun env ->
131
132 (* Load API credentials *)
133 let api_key =
134 try
135 let ic = open_in ".api-key" in
136 let key = String.trim (input_line ic) in
137 close_in ic; key
138 with
139 | Sys_error _ -> failwith "Create .api-key file with your Fastmail token"
140 in
141
142 messages_example env (`Bearer api_key)
143
144let () =
145 match main () with
146 | Ok () ->
147 printf "\n🎉 Revolutionary messages example completed!\n";
148 exit 0
149 | Error error ->
150 printf "\n"; show_error error;
151 printf "\n💡 Check the error details above\n";
152 exit 1