Skip to main content

Crate mailrs_jmap

Crate mailrs_jmap 

Source
Expand description

§mailrs-jmap

Server-side JMAP (RFC 8620 + RFC 8621) dispatcher and method handlers, decoupled from any specific web framework or backing store.

Plug your store in by implementing MailStore (async, object-safe), then call dispatch_request / dispatch_method from your HTTP handler.

§What’s covered

  • Mailbox/get, Mailbox/query (RFC 8621 §2)
  • Email/get, Email/query, Email/set (RFC 8621 §4)
  • Thread/get (RFC 8621 §3)
  • EmailSubmission/set (RFC 8621 §7) — create only
  • Method back-references (RFC 8620 §3.7)

§What’s not

  • JMAP push (event source / WebSocket) — the wire format is up to you because event sourcing is so deeply coupled to your runtime; this crate stays out of it.
  • JMAP-Contacts, JMAP-Calendars — different spec families.
  • Server-side capabilities object — you choose what to advertise; the JMAP_*_CAP constants give you the canonical URIs.

§Quick start

use async_trait::async_trait;
use mailrs_jmap::{
    dispatch_request, JmapRequest, MailStore,
    types::{Mailbox, MailboxCounts, Message, ParsedBody, SubmissionResult},
};

struct MyStore;

#[async_trait]
impl MailStore for MyStore {
    async fn list_mailboxes(&self, _user: &str) -> Result<Vec<Mailbox>, mailrs_jmap::store::StoreError> {
        Ok(vec![])
    }
    async fn mailbox_status(&self, _id: i64) -> Result<MailboxCounts, mailrs_jmap::store::StoreError> {
        Ok(MailboxCounts::default())
    }
    async fn list_messages(&self, _: i64, _: u32, _: u32) -> Result<Vec<Message>, mailrs_jmap::store::StoreError> { Ok(vec![]) }
    async fn get_message_by_db_id(&self, _: &str, _: i64) -> Result<Option<Message>, mailrs_jmap::store::StoreError> { Ok(None) }
    async fn list_thread_messages(&self, _: &str, _: &str) -> Result<Vec<Message>, mailrs_jmap::store::StoreError> { Ok(vec![]) }
    async fn update_flags(&self, _: i64, _: u32, _: u32) -> Result<(), mailrs_jmap::store::StoreError> { Ok(()) }
    async fn add_flags(&self, _: i64, _: u32, _: u32) -> Result<(), mailrs_jmap::store::StoreError> { Ok(()) }
    async fn read_message_raw(&self, _: &Message) -> Option<Vec<u8>> { None }
    fn parse_message(&self, _: &[u8]) -> ParsedBody { ParsedBody::default() }
    async fn submit_message(&self, _: &str, _: &Message, _: &[u8]) -> SubmissionResult {
        SubmissionResult { success: false, message: Some("not implemented".into()) }
    }
}

let store = MyStore;
let req: JmapRequest = serde_json::from_str(r#"{
    "using": ["urn:ietf:params:jmap:mail"],
    "methodCalls": [["Mailbox/get", {}, "c1"]]
}"#).unwrap();
let resp = dispatch_request(req, "alice@example.com", &store).await;

Re-exports§

pub use dispatch::dispatch_method;
pub use dispatch::dispatch_request;
pub use dispatch::JmapRequest;
pub use dispatch::JmapResponse;
pub use dispatch::JMAP_CORE_CAP;
pub use dispatch::JMAP_MAIL_CAP;
pub use dispatch::JMAP_SUBMISSION_CAP;
pub use error::JmapMethodError;
pub use store::MailStore;
pub use store::StoreError;

Modules§

build
Build JMAP Email object from a Message (+ optional parsed body).
dispatch
Top-level method dispatcher.
error
JMAP standard method errors (RFC 8620 §3.6.2).
fixtures
In-memory MailStore implementation suitable for tests, examples, and downstream-consumer test harnesses.
flags
Bitmask <-> JMAP keyword conversions (RFC 8621 §4.1).
ids
JMAP id parsers.
methods
Per-method JMAP handlers (RFC 8621).
refs
Resolve back-references between method calls within one JMAP request (RFC 8620 §3.7 “Back-references”).
store
The MailStore trait: the abstraction layer between JMAP method handlers and any backing store (PostgreSQL + Maildir, IMAP proxy, etc.).
types
Minimal JMAP-facing data types.