Skip to main content

MailStore

Trait MailStore 

Source
pub trait MailStore: Send + Sync {
    // Required methods
    fn list_mailboxes<'life0, 'life1, 'async_trait>(
        &'life0 self,
        user: &'life1 str,
    ) -> Pin<Box<dyn Future<Output = Result<Vec<Mailbox>, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn mailbox_status<'life0, 'async_trait>(
        &'life0 self,
        mailbox_id: i64,
    ) -> Pin<Box<dyn Future<Output = Result<MailboxCounts, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
    fn list_messages<'life0, 'async_trait>(
        &'life0 self,
        mailbox_id: i64,
        offset: u32,
        limit: u32,
    ) -> Pin<Box<dyn Future<Output = Result<Vec<Message>, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
    fn get_message_by_db_id<'life0, 'life1, 'async_trait>(
        &'life0 self,
        user: &'life1 str,
        id: i64,
    ) -> Pin<Box<dyn Future<Output = Result<Option<Message>, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn list_thread_messages<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        user: &'life1 str,
        thread_id: &'life2 str,
    ) -> Pin<Box<dyn Future<Output = Result<Vec<Message>, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;
    fn update_flags<'life0, 'async_trait>(
        &'life0 self,
        mailbox_id: i64,
        uid: u32,
        flags: u32,
    ) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
    fn add_flags<'life0, 'async_trait>(
        &'life0 self,
        mailbox_id: i64,
        uid: u32,
        flags: u32,
    ) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
    fn read_message_raw<'life0, 'life1, 'async_trait>(
        &'life0 self,
        message: &'life1 Message,
    ) -> Pin<Box<dyn Future<Output = Option<Vec<u8>>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn parse_message(&self, raw: &[u8]) -> ParsedBody;
    fn submit_message<'life0, 'life1, 'life2, 'life3, 'async_trait>(
        &'life0 self,
        user: &'life1 str,
        message: &'life2 Message,
        raw: &'life3 [u8],
    ) -> Pin<Box<dyn Future<Output = SubmissionResult> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait,
             'life3: 'async_trait;
}
Expand description

Storage operations every JMAP method handler in this crate needs.

One implementation per backing store (e.g. PostgreSQL + Maildir, IMAP proxy, in-memory test fixture). Method handlers reach the store via &dyn MailStore, so the trait is async, object-safe, and Send + Sync.

Identity conventions:

  • user is the authenticated owner’s full email address — handler code never invents one; auth resolution is the caller’s job.
  • mailbox_id / message id are the store’s native primary keys; the dispatcher renders them on the wire as mb-{id} / msg-{id}.
  • (mailbox_id, uid) is the IMAP-style addressing tuple used for the flag update methods.

Error contract: any returned StoreError is rendered into a JMAP serverFail method error with its Display value as description. The store is not expected to map errors itself.

Required Methods§

Source

fn list_mailboxes<'life0, 'life1, 'async_trait>( &'life0 self, user: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Vec<Mailbox>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

List all mailboxes for user. Used by Mailbox/get and Mailbox/query.

Source

fn mailbox_status<'life0, 'async_trait>( &'life0 self, mailbox_id: i64, ) -> Pin<Box<dyn Future<Output = Result<MailboxCounts, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Return (total, unread) for a mailbox. May be best-effort: handlers fall back to (0, 0) on error.

Source

fn list_messages<'life0, 'async_trait>( &'life0 self, mailbox_id: i64, offset: u32, limit: u32, ) -> Pin<Box<dyn Future<Output = Result<Vec<Message>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

List up to limit messages in mailbox_id starting at offset, ordered however the store deems natural (typically by uid).

Source

fn get_message_by_db_id<'life0, 'life1, 'async_trait>( &'life0 self, user: &'life1 str, id: i64, ) -> Pin<Box<dyn Future<Output = Result<Option<Message>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Look up a message by its database/primary id. Returns Ok(None) when the id exists but doesn’t belong to user, or when no such id exists.

Source

fn list_thread_messages<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, user: &'life1 str, thread_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<Vec<Message>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

All messages in thread_id for user, ordered chronologically.

Source

fn update_flags<'life0, 'async_trait>( &'life0 self, mailbox_id: i64, uid: u32, flags: u32, ) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Replace a message’s flag bitmask. mailbox_id + uid identify the row.

Source

fn add_flags<'life0, 'async_trait>( &'life0 self, mailbox_id: i64, uid: u32, flags: u32, ) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

OR flags into the message’s flag bitmask. Used to set \Deleted.

Source

fn read_message_raw<'life0, 'life1, 'async_trait>( &'life0 self, message: &'life1 Message, ) -> Pin<Box<dyn Future<Output = Option<Vec<u8>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Read the raw RFC 5322 bytes for a message. Returns None when not available (e.g. blob missing on disk). Used to populate bodyValues, textBody, htmlBody, and the submission path.

Source

fn parse_message(&self, raw: &[u8]) -> ParsedBody

Parse raw bytes into text/html body plus attachment metadata. Pulled out of Self::read_message_raw so the same bytes can serve both Email/get rendering and EmailSubmission/set outbound delivery.

Source

fn submit_message<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, user: &'life1 str, message: &'life2 Message, raw: &'life3 [u8], ) -> Pin<Box<dyn Future<Output = SubmissionResult> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Submit a previously-stored email through the outbound queue.

The handler has already resolved the Message and read its raw bytes via Self::read_message_raw; the store implementation is responsible for queueing / signing / actually sending.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§