mailrs_jmap/lib.rs
1#![deny(missing_docs)]
2#![deny(rustdoc::broken_intra_doc_links)]
3
4//! # mailrs-jmap
5//!
6//! Server-side JMAP (RFC 8620 + RFC 8621) dispatcher and method handlers,
7//! decoupled from any specific web framework or backing store.
8//!
9//! Plug your store in by implementing [`MailStore`] (async, object-safe), then
10//! call [`dispatch_request`] / [`dispatch_method`] from your HTTP handler.
11//!
12//! ## What's covered
13//!
14//! - `Mailbox/get`, `Mailbox/query` (RFC 8621 §2)
15//! - `Email/get`, `Email/query`, `Email/set` (RFC 8621 §4)
16//! - `Thread/get` (RFC 8621 §3)
17//! - `EmailSubmission/set` (RFC 8621 §7) — create only
18//! - Method back-references (RFC 8620 §3.7)
19//!
20//! ## What's not
21//!
22//! - JMAP push (event source / WebSocket) — the wire format is up to you
23//! because event sourcing is so deeply coupled to your runtime; this crate
24//! stays out of it.
25//! - JMAP-Contacts, JMAP-Calendars — different spec families.
26//! - Server-side capabilities object — you choose what to advertise; the
27//! `JMAP_*_CAP` constants give you the canonical URIs.
28//!
29//! ## Quick start
30//!
31//! ```no_run
32//! use async_trait::async_trait;
33//! use mailrs_jmap::{
34//! dispatch_request, JmapRequest, MailStore,
35//! types::{Mailbox, MailboxCounts, Message, ParsedBody, SubmissionResult},
36//! };
37//!
38//! struct MyStore;
39//!
40//! #[async_trait]
41//! impl MailStore for MyStore {
42//! async fn list_mailboxes(&self, _user: &str) -> Result<Vec<Mailbox>, mailrs_jmap::store::StoreError> {
43//! Ok(vec![])
44//! }
45//! async fn mailbox_status(&self, _id: i64) -> Result<MailboxCounts, mailrs_jmap::store::StoreError> {
46//! Ok(MailboxCounts::default())
47//! }
48//! async fn list_messages(&self, _: i64, _: u32, _: u32) -> Result<Vec<Message>, mailrs_jmap::store::StoreError> { Ok(vec![]) }
49//! async fn get_message_by_db_id(&self, _: &str, _: i64) -> Result<Option<Message>, mailrs_jmap::store::StoreError> { Ok(None) }
50//! async fn list_thread_messages(&self, _: &str, _: &str) -> Result<Vec<Message>, mailrs_jmap::store::StoreError> { Ok(vec![]) }
51//! async fn update_flags(&self, _: i64, _: u32, _: u32) -> Result<(), mailrs_jmap::store::StoreError> { Ok(()) }
52//! async fn add_flags(&self, _: i64, _: u32, _: u32) -> Result<(), mailrs_jmap::store::StoreError> { Ok(()) }
53//! async fn read_message_raw(&self, _: &Message) -> Option<Vec<u8>> { None }
54//! fn parse_message(&self, _: &[u8]) -> ParsedBody { ParsedBody::default() }
55//! async fn submit_message(&self, _: &str, _: &Message, _: &[u8]) -> SubmissionResult {
56//! SubmissionResult { success: false, message: Some("not implemented".into()) }
57//! }
58//! }
59//!
60//! # async fn run() {
61//! let store = MyStore;
62//! let req: JmapRequest = serde_json::from_str(r#"{
63//! "using": ["urn:ietf:params:jmap:mail"],
64//! "methodCalls": [["Mailbox/get", {}, "c1"]]
65//! }"#).unwrap();
66//! let resp = dispatch_request(req, "alice@example.com", &store).await;
67//! # let _ = resp;
68//! # }
69//! ```
70
71pub mod build;
72pub mod dispatch;
73pub mod error;
74pub mod fixtures;
75pub mod flags;
76pub mod ids;
77pub mod methods;
78pub mod refs;
79pub mod store;
80pub mod types;
81
82pub use dispatch::{
83 dispatch_method, dispatch_request, JmapRequest, JmapResponse, JMAP_CORE_CAP, JMAP_MAIL_CAP,
84 JMAP_SUBMISSION_CAP,
85};
86pub use error::JmapMethodError;
87pub use store::{MailStore, StoreError};