My agentic slop goes here. Not intended for anyone else!

JMAP Email Types JSON Implementation#

This document summarizes the JSON serialization and deserialization functionality added to the JMAP Email types implementation.

Overview#

JSON support has been added to the core email types in jmap-email/jmap_email_types.ml to enable proper serialization and parsing of JMAP email objects according to RFC 8621.

Implemented Types#

1. Email_address#

  • to_json: Converts email addresses to JSON with email (required) and name (optional) fields
  • of_json: Parses JSON objects into email address structures
  • Handles both named ({"name": "John Doe", "email": "john@example.com"}) and unnamed ({"email": "jane@example.com"}) addresses

2. Email_header#

  • to_json: Converts header fields to JSON with name and value fields
  • of_json: Parses JSON objects into header field structures
  • Example: {"name": "Subject", "value": "Important Message"}

3. Email_body_part#

  • to_json: Converts body parts to comprehensive JSON representation including:
    • Basic fields: partId, blobId, size, headers, type
    • Optional fields: name, charset, disposition, cid, language, location
    • Nested structures: subParts for multipart content
    • Extension fields: other_headers for custom headers
  • of_json: Parses complex JSON structures back into body part objects
  • Handles recursive parsing for nested multipart structures

4. Keywords#

  • to_json: Converts keyword sets to JMAP wire format (object with boolean values)
  • of_json: Parses JMAP keyword objects back into keyword lists
  • Supports all JMAP standard keywords and custom keywords
  • Example: {"$seen": true, "$flagged": false, "custom-label": true}

5. Email#

  • to_json: Converts complete email objects to JSON with all present fields:
    • Metadata: id, blobId, threadId, size, receivedAt
    • Addressing: from, to, cc, mailboxIds
    • Content: subject, preview, hasAttachment
    • Structure: textBody, htmlBody, attachments
    • Keywords and message IDs
  • of_json: Parses comprehensive email JSON into email objects
  • Handles optional fields correctly (present vs null vs missing)

Key Features#

Type Safety#

  • All functions use OCaml's strong type system to ensure correctness
  • Proper error handling with descriptive failure messages
  • Optional field handling that respects JMAP semantics

JMAP Compliance#

  • Follows RFC 8621 JSON structure specifications exactly
  • Handles JMAP-specific data types (dates as floats, boolean maps, etc.)
  • Supports all standard and extended JMAP email properties

Robustness#

  • Handles nested and recursive structures (body parts with sub-parts)
  • Proper handling of optional vs. null vs. missing fields
  • Extension field support for future JMAP enhancements

Testing#

Comprehensive test suite included in jmap-email/test_email_json.ml:

Test Coverage#

  1. Round-trip testing: JSON → OCaml → JSON conversion verification
  2. Field handling: Optional, null, and missing field scenarios
  3. Complex structures: Nested body parts, multiple addresses, keyword sets
  4. Real-world examples: RFC-compliant JMAP email JSON parsing
  5. Edge cases: Empty lists, minimal vs. full email objects

Test Types#

  • Unit tests for individual type conversions
  • Integration tests with realistic JMAP email examples
  • Round-trip verification to ensure data preservation
  • Property-based testing for JSON field ordering independence

Usage Examples#

Basic Email Address Parsing#

let json = `Assoc [("name", `String "John Doe"); ("email", `String "john@example.com")]
let addr = Email_address.of_json json
let back_to_json = Email_address.to_json addr

Complete Email Object Handling#

let email_json = Yojson.Safe.from_string {|
  {
    "id": "M123",
    "subject": "Test",
    "from": [{"name": "Alice", "email": "alice@example.com"}],
    "keywords": {"$seen": true, "$flagged": false}
  }
|}
let email = Email.of_json email_json
let roundtrip = Email.to_json email

Body Part Structure Parsing#

let body_part_json = Yojson.Safe.from_string {|
  {
    "partId": "1",
    "type": "text/plain", 
    "size": 1024,
    "headers": [{"name": "Content-Type", "value": "text/plain"}],
    "charset": "utf-8"
  }
|}
let part = Email_body_part.of_json body_part_json

Implementation Notes#

  • Uses manual JSON handling for precise control over structure
  • Leverages Yojson.Safe for JSON processing
  • Hashtbl used for ID maps and keyword storage as per JMAP library patterns
  • Date handling uses float values per JMAP specification
  • Error messages are descriptive for debugging JSON structure issues

This implementation provides a solid foundation for JMAP email processing with full JSON serialization support.