My agentic slop goes here. Not intended for anyone else!
at jsont 6.7 kB view raw
1open Printf 2 3(* Result monad operator for cleaner error handling *) 4let (let+) x f = Result.bind x f 5 6let fetch_recent_emails env ctx session = 7 try 8 let account_id_str = Jmap_unix.Session_utils.get_primary_mail_account session in 9 let account_id = match Jmap.Id.of_string account_id_str with 10 | Ok id -> id 11 | Error err -> failwith ("Invalid account ID: " ^ err) in 12 printf "Using account: %s\nBuilding JMAP request using type-safe capabilities...\n" account_id_str; 13 14 let query_json = 15 Jmap_email.Query.(query () |> with_account account_id |> order_by Sort.by_date_desc |> limit 5 |> build_email_query) in 16 17 let get_json = 18 Jmap_email.Query.(build_email_get_with_ref ~account_id 19 ~properties:[`Id; `ThreadId; `From; `Subject; `ReceivedAt; `Preview; `Keywords; `HasAttachment] 20 ~result_of:"q1") in 21 22 let builder = Jmap_unix.build ctx in 23 let builder = Jmap_unix.using builder [`Core; `Mail] in 24 let builder = Jmap_unix.add_method_call builder `Email_query query_json "q1" in 25 let builder = Jmap_unix.add_method_call builder `Email_get get_json "g1" in 26 27 let+ response = Jmap_unix.execute env builder in 28 printf "✓ Got JMAP response\n"; 29 30 let+ query_response_json = Jmap_unix.Response.extract_method ~method_name:`Email_query ~method_call_id:"q1" response in 31 let+ query_response = Jmap_email.Response.parse_query_response query_response_json in 32 printf "✓ Found %d emails\n\n" (Jmap_email.Response.ids_from_query_response query_response |> List.length); 33 34 let+ get_response_json = Jmap_unix.Response.extract_method ~method_name:`Email_get ~method_call_id:"g1" response in 35 let+ get_response = Jmap_email.Response.parse_get_response 36 ~from_json:(fun json -> match Jmap_email.Email.of_json json with 37 | Ok email -> email 38 | Error err -> failwith ("Email parse error: " ^ err)) 39 get_response_json in 40 41 let emails = Jmap_email.Response.emails_from_get_response get_response in 42 43 let print_sender email = 44 Jmap_email.Email.(match from email with 45 | Some (sender :: _) -> 46 Jmap_email.Address.(printf " From: %s\n" 47 (match name sender with | Some n -> n ^ " <" ^ email sender ^ ">" | None -> email sender)) 48 | _ -> printf " From: (Unknown)\n") in 49 50 let print_preview email = 51 Jmap_email.Email.(match preview email with 52 | Some p when String.length p > 0 -> 53 let preview = if String.length p > 100 then String.sub p 0 97 ^ "..." else p in 54 printf " Preview: %s\n" preview 55 | _ -> ()) in 56 57 List.iteri (fun i email -> 58 printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\nEmail #%d:\n" (i + 1); 59 printf " Subject: %s\n" (Jmap_email.Email.subject email |> Option.value ~default:"(No Subject)"); 60 print_sender email; 61 Jmap_email.Email.(received_at email |> Option.iter (fun t -> 62 printf " Date: %s\n" (Jmap.Date.to_rfc3339 t))); 63 print_preview email 64 ) emails; 65 printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"; 66 Ok () 67 with 68 | exn -> Error (Jmap.Error.protocol_error ("Exception: " ^ Printexc.to_string exn)) 69 70let main () = 71 (* Initialize the random number generator for TLS *) 72 Mirage_crypto_rng_unix.use_default (); 73 74 Eio_main.run @@ fun env -> 75 76 printf "JMAP Fastmail Connection & Foundation Test\n"; 77 printf "==========================================\n\n"; 78 79 (* Test basic JMAP types first *) 80 printf "Testing core JMAP modules...\n"; 81 82 let test_modules = [ 83 ("Jmap.Id", Jmap.Id.(of_string "test-id-123" |> Result.map (Format.asprintf "%a" pp))); 84 ("Jmap.Date", Ok (Jmap.Date.(Unix.time () |> of_timestamp |> to_timestamp |> Printf.sprintf "%.0f"))); 85 ("Jmap.UInt", Jmap.UInt.(of_int 42 |> Result.map (Format.asprintf "%a" pp))); 86 ] in 87 88 let test_results = List.map (fun (name, result) -> match result with 89 | Ok value -> printf "✓ %s creation: %s\n" name value; true 90 | Error e -> printf "✗ %s creation failed: %s\n" name e; false 91 ) test_modules in 92 93 if not (List.for_all (fun x -> x) test_results) then ( 94 printf "\nCore module tests failed - aborting\n"; 95 exit 1 96 ); 97 98 printf "✓ All core modules working\n\n"; 99 100 (* Read API credentials *) 101 let api_key = 102 try 103 let ic = open_in ".api-key" in 104 let key = input_line ic in 105 close_in ic; 106 String.trim key 107 with 108 | Sys_error _ -> 109 eprintf "Info: Create a .api-key file with your JMAP bearer token to test full connectivity\n"; 110 eprintf " You can get this from Fastmail Settings > Privacy & Security > API Keys\n\n"; 111 printf "Overall: ALL TESTS PASSED\n"; 112 printf "\nOffline test complete - all core JMAP functionality working!\n"; 113 exit 0 114 in 115 116 try 117 (* Step 1: Connect to JMAP server *) 118 printf "Connecting to Fastmail JMAP server...\n"; 119 let client = Jmap_unix.create_client () in 120 let session_url = Uri.of_string "https://api.fastmail.com/jmap/session" in 121 let auth_method = Jmap_unix.Bearer api_key in 122 123 match Jmap_unix.(connect env client ~session_url ~host:"api.fastmail.com" ~port:443 ~use_tls:true ~auth_method ()) with 124 | Ok (ctx, session) -> 125 printf "✓ Connected successfully\n\n"; 126 Jmap_unix.Session_utils.print_session_info session; 127 128 printf "\n📧 Fetching recent emails...\n"; 129 (match fetch_recent_emails env ctx session with 130 | Ok () -> printf "✓ Email fetch completed successfully\n" 131 | Error error -> Format.printf "⚠ Email fetch failed: %a\n" Jmap.Error.pp error); 132 133 printf "\nClosing connection...\n"; 134 (match Jmap_unix.close ctx with 135 | Ok () -> printf "✓ Connection closed successfully\n" 136 | Error error -> Format.printf "⚠ Error closing connection: %a\n" Jmap.Error.pp error); 137 138 printf "\nOverall: ALL TESTS PASSED\n" 139 140 | Error error -> 141 Format.eprintf "✗ Connection failed: %a\n" 142 Jmap.Error.pp error; 143 eprintf "\nThis could be due to:\n"; 144 eprintf " - Invalid API key\n"; 145 eprintf " - Network connectivity issues\n"; 146 eprintf " - Fastmail service unavailability\n\n"; 147 exit 1 148 149 with 150 | Failure msg -> 151 printf "Error: %s\n" msg; 152 exit 1 153 | exn -> 154 printf "Unexpected error: %s\n" (Printexc.to_string exn); 155 exit 1 156 157let () = main ()