Skip to main content

smbcloud_model/
mail.rs

1use {
2    chrono::{DateTime, Utc},
3    serde::{Deserialize, Serialize},
4    serde_repr::{Deserialize_repr, Serialize_repr},
5    std::{collections::HashMap, fmt::Display},
6};
7
8#[derive(Deserialize_repr, Serialize_repr, Debug, Clone, Copy, PartialEq, Eq, Default)]
9#[repr(u8)]
10pub enum MailStatus {
11    #[default]
12    PendingDns = 0,
13    Active = 1,
14    Suspended = 2,
15}
16
17impl Display for MailStatus {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        match self {
20            MailStatus::PendingDns => write!(f, "pending_dns"),
21            MailStatus::Active => write!(f, "active"),
22            MailStatus::Suspended => write!(f, "suspended"),
23        }
24    }
25}
26
27#[derive(Deserialize_repr, Serialize_repr, Debug, Clone, Copy, PartialEq, Eq, Default)]
28#[repr(u8)]
29pub enum MailMessageStatus {
30    #[default]
31    Received = 0,
32    Forwarded = 1,
33    ForwardFailed = 2,
34}
35
36impl Display for MailMessageStatus {
37    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38        match self {
39            MailMessageStatus::Received => write!(f, "received"),
40            MailMessageStatus::Forwarded => write!(f, "forwarded"),
41            MailMessageStatus::ForwardFailed => write!(f, "forward_failed"),
42        }
43    }
44}
45
46#[derive(Deserialize, Serialize, Debug, Clone)]
47pub struct MailApp {
48    // UUIDs, not sequence numbers. The API moved mail_apps, mail_inboxes and
49    // mail_messages onto UUID primary keys; leaving these as i32 made every
50    // `smb mail *` command and every mail MCP tool fail to deserialize with
51    // "invalid type: string ..., expected i32". tenant_id and project_id are
52    // still integers.
53    pub id: String,
54    pub name: String,
55    pub domain: String,
56    pub aws_region: String,
57    pub project_id: i32,
58    pub tenant_id: i32,
59    pub created_at: DateTime<Utc>,
60    pub updated_at: DateTime<Utc>,
61    pub status: MailStatus,
62    pub ses_inbound_mx_value: String,
63    pub inbound_bucket_name: String,
64    pub inbound_email_key_prefix: String,
65    #[serde(default)]
66    pub lambda_config: HashMap<String, String>,
67    #[serde(default)]
68    pub inboxes: Vec<MailInbox>,
69}
70
71#[derive(Deserialize, Serialize, Debug, Clone)]
72pub struct MailInbox {
73    pub id: String,
74    pub local_part: String,
75    pub full_address: String,
76    pub inbox_email: String,
77    pub sender_email: String,
78    pub forward_to_email: String,
79    pub mail_app_id: String,
80    pub project_id: i32,
81    pub tenant_id: i32,
82    pub last_test_email_sent_at: Option<DateTime<Utc>>,
83    pub created_at: DateTime<Utc>,
84    pub updated_at: DateTime<Utc>,
85    pub status: MailStatus,
86    pub email_key_prefix: String,
87    #[serde(default)]
88    pub lambda_config: HashMap<String, String>,
89}
90
91#[derive(Deserialize, Serialize, Debug, Clone)]
92pub struct MailMessage {
93    pub id: String,
94    pub mail_inbox_id: String,
95    pub provider_message_id: String,
96    pub original_recipient_email: String,
97    pub from_email: String,
98    pub from_name: Option<String>,
99    pub subject: Option<String>,
100    pub text_preview: Option<String>,
101    pub size_bytes: Option<i64>,
102    pub forwarded_at: Option<DateTime<Utc>>,
103    pub forward_error: Option<String>,
104    pub received_at: DateTime<Utc>,
105    pub created_at: DateTime<Utc>,
106    pub updated_at: DateTime<Utc>,
107    pub status: MailMessageStatus,
108    pub text_body: Option<String>,
109    pub html_body: Option<String>,
110    #[serde(default)]
111    pub to_emails: Vec<String>,
112    #[serde(default)]
113    pub cc_emails: Vec<String>,
114    #[serde(default)]
115    pub forward_recipients: Vec<String>,
116    #[serde(default)]
117    pub headers_json: HashMap<String, String>,
118    pub s3_bucket: Option<String>,
119    pub s3_key: Option<String>,
120}
121
122#[derive(Serialize, Debug, Clone)]
123pub struct MailAppCreate {
124    pub name: String,
125    pub project_id: String,
126    pub domain: String,
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub aws_region: Option<String>,
129}
130
131#[derive(Serialize, Debug, Clone, Default)]
132pub struct MailAppUpdate {
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub name: Option<String>,
135    #[serde(skip_serializing_if = "Option::is_none")]
136    pub domain: Option<String>,
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub aws_region: Option<String>,
139}
140
141impl MailAppUpdate {
142    pub fn is_empty(&self) -> bool {
143        self.name.is_none() && self.domain.is_none() && self.aws_region.is_none()
144    }
145}
146
147#[derive(Serialize, Debug, Clone)]
148pub struct MailInboxCreate {
149    pub local_part: String,
150    pub forward_to_email: String,
151    #[serde(skip_serializing_if = "Option::is_none")]
152    pub sender_email: Option<String>,
153}
154
155#[derive(Serialize, Debug, Clone, Default)]
156pub struct MailInboxUpdate {
157    #[serde(skip_serializing_if = "Option::is_none")]
158    pub local_part: Option<String>,
159    #[serde(skip_serializing_if = "Option::is_none")]
160    pub forward_to_email: Option<String>,
161    #[serde(skip_serializing_if = "Option::is_none")]
162    pub sender_email: Option<String>,
163}
164
165impl MailInboxUpdate {
166    pub fn is_empty(&self) -> bool {
167        self.local_part.is_none() && self.forward_to_email.is_none() && self.sender_email.is_none()
168    }
169}
170
171#[derive(Serialize, Debug, Clone, Default)]
172pub struct MailTestEmailRequest {
173    #[serde(skip_serializing_if = "Option::is_none")]
174    pub recipient_email: Option<String>,
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub subject: Option<String>,
177    #[serde(skip_serializing_if = "Option::is_none")]
178    pub body: Option<String>,
179}
180
181#[derive(Deserialize, Serialize, Debug, Clone)]
182pub struct MailTestEmailDelivery {
183    pub message_id: String,
184    pub recipient_email: String,
185    pub delivery_method: String,
186    pub sent_at: String,
187}