Skip to main content

esi_openapi/groups/
mail.rs

1#![allow(unused)]
2
3use crate::prelude::*;
4
5/// Endpoints for Mail
6pub struct MailGroup<'a> {
7    pub(crate) esi: &'a Esi,
8}
9
10#[derive(Debug, Deserialize, Serialize, Clone)]
11/// Information about all mail labels.
12pub struct MailLabels {
13    /// List of individual mail labels.
14    #[serde(default)]
15    pub labels: Vec<MailLabel>,
16    /// Total unread count across all labels.
17    pub total_unread_count: Option<i64>,
18}
19
20#[derive(Debug, Deserialize, Serialize, Clone)]
21/// Information about an individual mail label.
22pub struct MailLabel {
23    /// Color of the label as RGB Hex (`#rrggbb`).
24    pub color: String,
25    /// ID of the label.
26    pub label_id: i64,
27    /// Name of the label.
28    pub name: String,
29    /// Number of unread messages with this label.
30    #[serde(default)]
31    pub unread_count: Option<i64>,
32}
33
34#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)]
35/// The kind of entity a mail is addressed to.
36pub enum RecipientType {
37    /// An alliance.
38    #[serde(rename = "alliance")]
39    Alliance,
40    /// A character.
41    #[serde(rename = "character")]
42    Character,
43    /// A corporation.
44    #[serde(rename = "corporation")]
45    Corporation,
46    /// A mailing list.
47    #[serde(rename = "mailing_list")]
48    MailingList,
49    /// A value not known to this version of the crate.
50    #[serde(other)]
51    Unrecognized,
52}
53
54#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
55/// A recipient of a mail.
56pub struct MailRecipient {
57    /// ID of the recipient.
58    pub recipient_id: i64,
59    /// Kind of the recipient.
60    pub recipient_type: RecipientType,
61}
62
63#[derive(Debug, Deserialize, Serialize, Clone)]
64/// A mail header, as returned by the mail list.
65pub struct MailHeader {
66    /// Character ID of the sender.
67    pub from: Option<i64>,
68    /// Whether the mail has been read.
69    pub is_read: Option<bool>,
70    /// Label IDs attached to the mail.
71    #[serde(default)]
72    pub labels: Vec<i64>,
73    /// ID of the mail.
74    pub mail_id: Option<i64>,
75    /// Recipients of the mail.
76    #[serde(default)]
77    pub recipients: Vec<MailRecipient>,
78    /// Subject of the mail.
79    pub subject: Option<String>,
80    /// Date and time the mail was sent.
81    pub timestamp: Option<String>,
82}
83
84#[derive(Debug, Deserialize, Serialize, Clone)]
85/// A full mail, as returned by the mail details endpoint.
86pub struct Mail {
87    /// Body of the mail.
88    pub body: Option<String>,
89    /// Character ID of the sender.
90    pub from: Option<i64>,
91    /// Label IDs attached to the mail.
92    #[serde(default)]
93    pub labels: Vec<i64>,
94    /// Whether the mail has been read.
95    pub read: Option<bool>,
96    /// Recipients of the mail.
97    #[serde(default)]
98    pub recipients: Vec<MailRecipient>,
99    /// Subject of the mail.
100    pub subject: Option<String>,
101    /// Date and time the mail was sent.
102    pub timestamp: Option<String>,
103}
104
105#[derive(Debug, Serialize, Clone)]
106/// The body of a request to send a new mail.
107pub struct NewMail {
108    /// Body of the mail.
109    pub body: String,
110    /// Recipients of the mail.
111    pub recipients: Vec<MailRecipient>,
112    /// Subject of the mail.
113    pub subject: String,
114    /// Maximum CSPA charge (in ISK) the sender accepts to pay.
115    #[serde(skip_serializing_if = "Option::is_none")]
116    pub approved_cost: Option<i64>,
117}
118
119#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)]
120/// The colors allowed for a mail label.
121pub enum MailLabelColor {
122    /// `#0000fe`
123    #[serde(rename = "#0000fe")]
124    Blue,
125    /// `#006634`
126    #[serde(rename = "#006634")]
127    DarkGreen,
128    /// `#0099ff`
129    #[serde(rename = "#0099ff")]
130    LightBlue,
131    /// `#00ff33`
132    #[serde(rename = "#00ff33")]
133    BrightGreen,
134    /// `#01ffff`
135    #[serde(rename = "#01ffff")]
136    Cyan,
137    /// `#349800`
138    #[serde(rename = "#349800")]
139    Green,
140    /// `#660066`
141    #[serde(rename = "#660066")]
142    Purple,
143    /// `#666666`
144    #[serde(rename = "#666666")]
145    DarkGrey,
146    /// `#999999`
147    #[serde(rename = "#999999")]
148    Grey,
149    /// `#99ffff`
150    #[serde(rename = "#99ffff")]
151    PaleCyan,
152    /// `#9a0000`
153    #[serde(rename = "#9a0000")]
154    DarkRed,
155    /// `#ccff9a`
156    #[serde(rename = "#ccff9a")]
157    PaleGreen,
158    /// `#e6e6e6`
159    #[serde(rename = "#e6e6e6")]
160    LightGrey,
161    /// `#fe0000`
162    #[serde(rename = "#fe0000")]
163    Red,
164    /// `#ff6600`
165    #[serde(rename = "#ff6600")]
166    Orange,
167    /// `#ffff01`
168    #[serde(rename = "#ffff01")]
169    Yellow,
170    /// `#ffffcd`
171    #[serde(rename = "#ffffcd")]
172    PaleYellow,
173    /// `#ffffff`
174    #[serde(rename = "#ffffff")]
175    White,
176    /// A value not known to this version of the crate.
177    #[serde(other)]
178    Unrecognized,
179}
180
181#[derive(Debug, Serialize, Clone)]
182/// The body of a request to create a mail label.
183pub struct NewMailLabel {
184    /// Name of the label.
185    pub name: String,
186    /// Color of the label.
187    #[serde(skip_serializing_if = "Option::is_none")]
188    pub color: Option<MailLabelColor>,
189}
190
191#[derive(Debug, Serialize, Clone, Default)]
192/// The body of a request to update the metadata of a mail.
193pub struct MailUpdate {
194    /// Label IDs to set on the mail.
195    #[serde(skip_serializing_if = "Option::is_none")]
196    pub labels: Option<Vec<i64>>,
197    /// Whether the mail is read.
198    #[serde(skip_serializing_if = "Option::is_none")]
199    pub read: Option<bool>,
200}
201
202#[derive(Debug, Deserialize, Serialize, Clone)]
203/// A mailing list the character is subscribed to.
204pub struct MailingList {
205    /// ID of the mailing list.
206    pub mailing_list_id: i64,
207    /// Name of the mailing list.
208    pub name: String,
209}
210
211impl MailGroup<'_> {
212    api_get!(
213        /// Return the 50 most recent mail headers of a character.
214        ///
215        /// Use `labels` to filter by label and `last_mail_id` to page back
216        /// from the oldest mail already seen.
217        get_character_mail,
218        "GetCharactersCharacterIdMail",
219        RequestType::Authenticated,
220        Vec<MailHeader>,
221        (character_id: i64) => "{character_id}";
222        OptionalMany(labels: &[i64]) => "labels",
223        Optional(last_mail_id: i64) => "last_mail_id"
224    );
225
226    api_post!(
227        /// Send a new mail. Returns the ID of the created mail.
228        send_character_mail,
229        "PostCharactersCharacterIdMail",
230        RequestType::Authenticated,
231        i64,
232        (character_id: i64) => "{character_id}",
233        mail: &NewMail,
234    );
235
236    api_get!(
237        /// Return a list of the users mail labels, unread counts for each
238        /// label and a total unread count.
239        get_character_mail_labels,
240        "GetCharactersCharacterIdMailLabels",
241        RequestType::Authenticated,
242        MailLabels,
243        (character_id: i64) => "{character_id}"
244    );
245
246    api_post!(
247        /// Create a mail label. Returns the ID of the created label.
248        create_character_mail_label,
249        "PostCharactersCharacterIdMailLabels",
250        RequestType::Authenticated,
251        i64,
252        (character_id: i64) => "{character_id}",
253        label: &NewMailLabel,
254    );
255
256    api_delete!(
257        /// Delete a mail label.
258        delete_character_mail_label,
259        "DeleteCharactersCharacterIdMailLabelsLabelId",
260        RequestType::Authenticated,
261        (),
262        (character_id: i64) => "{character_id}",
263        (label_id: i64) => "{label_id}"
264    );
265
266    api_get!(
267        /// Return all mailing lists the character is subscribed to.
268        get_character_mailing_lists,
269        "GetCharactersCharacterIdMailLists",
270        RequestType::Authenticated,
271        Vec<MailingList>,
272        (character_id: i64) => "{character_id}"
273    );
274
275    api_delete!(
276        /// Delete a mail.
277        delete_character_mail,
278        "DeleteCharactersCharacterIdMailMailId",
279        RequestType::Authenticated,
280        (),
281        (character_id: i64) => "{character_id}",
282        (mail_id: i64) => "{mail_id}"
283    );
284
285    api_get!(
286        /// Return the contents of a single mail.
287        get_character_mail_by_id,
288        "GetCharactersCharacterIdMailMailId",
289        RequestType::Authenticated,
290        Mail,
291        (character_id: i64) => "{character_id}",
292        (mail_id: i64) => "{mail_id}"
293    );
294
295    api_put!(
296        /// Update the labels and read state of a mail.
297        update_character_mail,
298        "PutCharactersCharacterIdMailMailId",
299        RequestType::Authenticated,
300        (),
301        (character_id: i64) => "{character_id}",
302        (mail_id: i64) => "{mail_id}",
303        update: &MailUpdate,
304    );
305}
306
307#[cfg(test)]
308mod mail_tests {
309    use super::*;
310
311    #[test]
312    fn test_parse_mail_header_and_unknown_recipient() {
313        let json = r#"[{"from": 2112625428, "is_read": true, "labels": [3, 9000000000],
314            "mail_id": 7000000000, "subject": "Hi", "timestamp": "2026-10-01T00:00:00Z",
315            "recipients": [{"recipient_id": 1, "recipient_type": "mailing_list"},
316                           {"recipient_id": 2, "recipient_type": "something_new"}]}]"#;
317        let headers: Vec<MailHeader> = serde_json::from_str(json).unwrap();
318        assert_eq!(headers[0].mail_id, Some(7_000_000_000));
319        assert_eq!(
320            headers[0].recipients[0].recipient_type,
321            RecipientType::MailingList
322        );
323        assert_eq!(
324            headers[0].recipients[1].recipient_type,
325            RecipientType::Unrecognized
326        );
327    }
328
329    #[test]
330    fn test_serialize_new_mail_and_label() {
331        let mail = NewMail {
332            body: "b".into(),
333            recipients: vec![MailRecipient {
334                recipient_id: 1,
335                recipient_type: RecipientType::Character,
336            }],
337            subject: "s".into(),
338            approved_cost: None,
339        };
340        let v = serde_json::to_value(&mail).unwrap();
341        assert_eq!(v["recipients"][0]["recipient_type"], "character");
342        assert!(v.get("approved_cost").is_none());
343        let label = NewMailLabel {
344            name: "x".into(),
345            color: Some(MailLabelColor::Red),
346        };
347        assert_eq!(serde_json::to_value(&label).unwrap()["color"], "#fe0000");
348        let upd = MailUpdate {
349            labels: None,
350            read: Some(true),
351        };
352        assert_eq!(serde_json::to_string(&upd).unwrap(), r#"{"read":true}"#);
353    }
354
355    #[test]
356    fn test_parse_mail_and_lists() {
357        let m: Mail = serde_json::from_str(r#"{"body": "x", "from": 1, "read": false}"#).unwrap();
358        assert_eq!(m.read, Some(false));
359        let l: Vec<MailingList> =
360            serde_json::from_str(r#"[{"mailing_list_id": 5000000000, "name": "n"}]"#).unwrap();
361        assert_eq!(l[0].mailing_list_id, 5_000_000_000);
362    }
363}