mailrs_jmap/types.rs
1//! Minimal JMAP-facing data types.
2//!
3//! These are intentionally decoupled from any backing store (Maildir, IMAP, S3,
4//! whatever). A `MailStore` implementation is responsible for mapping its own
5//! representation into these shapes.
6//!
7//! ## Flag bitmask
8//!
9//! The `FLAG_*` constants mirror the wire-level numbering already used by
10//! mailrs-mailbox, so a server that wraps mailrs-mailbox can pass flags
11//! through without translation.
12
13use serde::{Deserialize, Serialize};
14
15/// Mailbox metadata as needed by JMAP's `Mailbox/get` and `Mailbox/query`.
16///
17/// `id` is the store's native primary key. The dispatcher renders it to the
18/// JMAP-visible id `mb-{id}`.
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct Mailbox {
21 /// Store-native primary key. Rendered on the wire as `mb-{id}`.
22 pub id: i64,
23 /// Human-visible mailbox name (e.g. `INBOX`, `Sent`, `Drafts`).
24 pub name: String,
25}
26
27/// Per-mailbox counts returned by [`crate::store::MailStore::mailbox_status`].
28#[derive(Debug, Clone, Copy, Default)]
29pub struct MailboxCounts {
30 /// Total number of messages in the mailbox.
31 pub total: u32,
32 /// Number of messages without the `\Seen` flag.
33 pub unread: u32,
34}
35
36/// A single message as JMAP needs to see it for `Email/get`, `Email/query`,
37/// `Email/set`, `Thread/get`, and `EmailSubmission/set`.
38///
39/// JMAP-visible email id is `msg-{id}`.
40#[derive(Debug, Clone)]
41pub struct Message {
42 /// Store-native primary key. Rendered on the wire as `msg-{id}`.
43 pub id: i64,
44 /// FK into the message's containing mailbox.
45 pub mailbox_id: i64,
46 /// IMAP-style UID within `mailbox_id`. Combined with `mailbox_id` it
47 /// uniquely identifies the row for flag updates.
48 pub uid: u32,
49 /// Raw `From:` header value, may include a display name (e.g.
50 /// `"Alice" <alice@example.com>`).
51 pub sender: String,
52 /// Raw `To:` header value. Comma-separated address list.
53 pub recipients: String,
54 /// Decoded `Subject:` header.
55 pub subject: String,
56 /// `Date:` header epoch seconds.
57 pub date: i64,
58 /// Message size in bytes.
59 pub size: u32,
60 /// Flag bitmask. See the `FLAG_*` constants in this module.
61 pub flags: u32,
62 /// Internal delivery time epoch seconds.
63 pub internal_date: i64,
64 /// `Message-ID:` header value, without the angle brackets.
65 pub message_id: String,
66 /// `In-Reply-To:` header value, without angle brackets, or empty when
67 /// the message is not a reply.
68 pub in_reply_to: String,
69 /// Store-defined thread identifier, stable across all messages in the same
70 /// conversation.
71 pub thread_id: String,
72 /// Owner's full address (used to read the raw bytes from a store).
73 pub user_address: String,
74 /// Optional pre-extracted plain-text snippet, used for `preview`.
75 pub new_content: Option<String>,
76 /// Implementation-defined opaque id used by [`crate::store::MailStore::read_message_raw`]
77 /// to locate the on-disk / blob copy of the message.
78 pub blob_id: String,
79}
80
81/// Parsed message body parts as returned by [`crate::store::MailStore::parse_message`].
82#[derive(Debug, Clone, Default)]
83pub struct ParsedBody {
84 /// Decoded `text/plain` body, if any.
85 pub text: Option<String>,
86 /// Decoded `text/html` body, if any.
87 pub html: Option<String>,
88 /// Attachment metadata (no body bytes — see [`Attachment`]).
89 pub attachments: Vec<Attachment>,
90}
91
92/// Attachment metadata exposed via JMAP's `Email/get` `attachments` property.
93///
94/// Body bytes are **not** included; if a client needs them it has to use a
95/// separate blob/download endpoint (out of scope for this crate).
96#[derive(Debug, Clone)]
97pub struct Attachment {
98 /// Suggested filename from the `Content-Disposition` header.
99 pub filename: String,
100 /// MIME type from the `Content-Type` header.
101 pub content_type: String,
102 /// Size in bytes of the (decoded) attachment payload.
103 pub size: u32,
104}
105
106/// Result of submitting a previously-stored email through the outbound queue.
107#[derive(Debug, Clone)]
108pub struct SubmissionResult {
109 /// `true` when the message was successfully queued for delivery.
110 pub success: bool,
111 /// Optional human-readable explanation. On failure this typically carries
112 /// the reason; on success it's `None`.
113 pub message: Option<String>,
114}
115
116/// IMAP `\Seen` flag — message has been viewed.
117pub const FLAG_SEEN: u32 = 0b0000_0001;
118/// IMAP `\Answered` flag — a reply has been sent.
119pub const FLAG_ANSWERED: u32 = 0b0000_0010;
120/// IMAP `\Flagged` flag — user-marked for follow-up.
121pub const FLAG_FLAGGED: u32 = 0b0000_0100;
122/// IMAP `\Deleted` flag — marked for purge on EXPUNGE.
123pub const FLAG_DELETED: u32 = 0b0000_1000;
124/// IMAP `\Draft` flag — composed but not yet sent.
125pub const FLAG_DRAFT: u32 = 0b0001_0000;