Skip to main content

io_jmap/rfc8621/
email_submission.rs

1//! JMAP for Mail: EmailSubmission (RFC 8621 §7).
2
3use core::fmt;
4
5use alloc::{collections::BTreeMap, string::String, vec::Vec};
6
7use serde::{Deserialize, Serialize};
8
9pub mod cancel;
10pub mod get;
11pub mod query;
12pub mod set;
13
14/// JMAP for Mail Submission capability (RFC 8621 §7).
15pub const JMAP_SUBMISSION_CAPABILITY: &str = "urn:ietf:params:jmap:submission";
16
17/// The undo status of an email submission (RFC 8621 §7.1).
18#[derive(Clone, Debug, Serialize, Deserialize)]
19#[serde(rename_all = "camelCase")]
20pub enum JmapUndoStatus {
21    /// The submission may still be cancelled.
22    Pending,
23    /// The submission can no longer be cancelled.
24    Final,
25    /// The submission was cancelled.
26    Canceled,
27}
28
29impl fmt::Display for JmapUndoStatus {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        match self {
32            Self::Pending => write!(f, "pending"),
33            Self::Final => write!(f, "final"),
34            Self::Canceled => write!(f, "canceled"),
35        }
36    }
37}
38
39/// A JMAP EmailSubmission object (RFC 8621 §7.1).
40///
41/// Represents a sending of an email from a particular identity.
42#[derive(Clone, Debug, Default, Serialize, Deserialize)]
43#[serde(rename_all = "camelCase")]
44pub struct JmapEmailSubmission {
45    /// Server-assigned ID.
46    pub id: Option<String>,
47    /// The identity to send as.
48    pub identity_id: Option<String>,
49    /// The ID of the email to send.
50    pub email_id: Option<String>,
51    /// The thread the email belongs to.
52    pub thread_id: Option<String>,
53    /// SMTP envelope to use for delivery.
54    pub envelope: Option<JmapEnvelope>,
55    /// Date/time the submission was made (RFC 3339).
56    pub send_at: Option<String>,
57    /// Current undo status: `"pending"`, `"final"`, or `"canceled"`.
58    pub undo_status: Option<JmapUndoStatus>,
59    /// Per-recipient delivery status.
60    pub delivery_status: Option<BTreeMap<String, JmapDeliveryStatus>>,
61    /// Blob IDs of DSN messages.
62    pub dsn_blob_ids: Option<Vec<String>>,
63    /// Blob IDs of MDN messages.
64    pub mdn_blob_ids: Option<Vec<String>>,
65}
66
67/// SMTP envelope for an email submission.
68#[derive(Clone, Debug, Serialize, Deserialize)]
69#[serde(rename_all = "camelCase")]
70pub struct JmapEnvelope {
71    /// MAIL FROM address and parameters.
72    pub mail_from: JmapEmailAddressWithParameters,
73    /// RCPT TO addresses and parameters.
74    pub rcpt_to: Vec<JmapEmailAddressWithParameters>,
75}
76
77/// An email address with optional SMTP parameters.
78#[derive(Clone, Debug, Serialize, Deserialize)]
79#[serde(rename_all = "camelCase")]
80pub struct JmapEmailAddressWithParameters {
81    /// The email address.
82    pub email: String,
83    /// SMTP parameters (e.g. `NOTIFY`, `ORCPT`).
84    pub parameters: Option<BTreeMap<String, Option<String>>>,
85}
86
87/// Delivery state of a single recipient (RFC 8621 §7.1.1).
88#[derive(Clone, Debug, Serialize, Deserialize)]
89#[serde(rename_all = "camelCase")]
90pub enum JmapDelivered {
91    /// The message is in a local mail queue.
92    Queued,
93    /// The message was successfully delivered.
94    Yes,
95    /// Delivery failed permanently.
96    No,
97    /// The delivery status is unknown.
98    Unknown,
99}
100
101/// Whether the email has been displayed to the recipient (RFC 8621 §7.1.1).
102#[derive(Clone, Debug, Serialize, Deserialize)]
103#[serde(rename_all = "camelCase")]
104pub enum JmapDisplayed {
105    /// Display status is unknown.
106    Unknown,
107    /// The message has been displayed.
108    Yes,
109    /// The message has not been displayed.
110    No,
111}
112
113/// Per-recipient delivery status from a submission.
114#[derive(Clone, Debug, Serialize, Deserialize)]
115#[serde(rename_all = "camelCase")]
116pub struct JmapDeliveryStatus {
117    /// The SMTP reply for this recipient.
118    pub smtp_reply: String,
119    /// Delivery state for this recipient.
120    pub delivered: JmapDelivered,
121    /// Whether the message has been displayed to the recipient.
122    pub displayed: JmapDisplayed,
123}
124
125/// Per-object error returned in `EmailSubmission/set` responses
126/// (RFC 8621 §7.5); shared by the create (`set`) and cancel flows.
127#[derive(Clone, Debug, Deserialize)]
128#[serde(tag = "type", rename_all = "camelCase")]
129pub enum JmapEmailSubmissionSetItemError {
130    /// The message had too many recipients (RFC 8621 §7.5).
131    TooManyRecipients {
132        /// Optional human-readable detail.
133        description: Option<String>,
134    },
135    /// The message had no recipients (RFC 8621 §7.5).
136    NoRecipients {
137        /// Optional human-readable detail.
138        description: Option<String>,
139    },
140    /// One or more recipient addresses were invalid (RFC 8621 §7.5).
141    InvalidRecipients {
142        /// Optional human-readable detail.
143        description: Option<String>,
144    },
145    /// The From address is not permitted for this identity (RFC 8621 §7.5).
146    ForbiddenFrom {
147        /// Optional human-readable detail.
148        description: Option<String>,
149    },
150    /// The MAIL FROM address is not permitted (RFC 8621 §7.5).
151    ForbiddenMailFrom {
152        /// Optional human-readable detail.
153        description: Option<String>,
154    },
155    /// This user is not permitted to send email (RFC 8621 §7.5).
156    ForbiddenToSend {
157        /// Optional human-readable detail.
158        description: Option<String>,
159    },
160    /// The submission cannot be unsent (RFC 8621 §7.5).
161    CannotUnsendMessage {
162        /// Optional human-readable detail.
163        description: Option<String>,
164    },
165    /// The email object was not a valid message (RFC 8621 §7.5).
166    InvalidEmail {
167        /// Optional human-readable detail.
168        description: Option<String>,
169    },
170    /// Standard set error (RFC 8620 §5.3): target id not found.
171    NotFound {
172        /// Optional human-readable detail.
173        description: Option<String>,
174    },
175    /// Standard set error (RFC 8620 §5.3): one or more properties were invalid.
176    InvalidProperties {
177        /// Optional human-readable detail.
178        description: Option<String>,
179        /// The invalid property names.
180        #[serde(default)]
181        properties: Vec<String>,
182    },
183    /// Catch-all for set errors not modelled above.
184    #[serde(other)]
185    Unknown,
186}