Skip to main content

sendry/resources/
inbound.rs

1//! Inbound email handling.
2
3use reqwest::Method;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7use crate::{client::Sendry, error::Error, Page, PaginationParams};
8
9/// Inbound resource handle.
10#[derive(Debug, Clone)]
11pub struct Inbound {
12    client: Sendry,
13}
14
15impl Inbound {
16    pub(crate) fn new(client: Sendry) -> Self {
17        Self { client }
18    }
19
20    /// List received inbound emails.
21    pub async fn list(&self, params: PaginationParams) -> Result<Page<InboundEmail>, Error> {
22        let q = params.to_query();
23        self.client
24            .request(self.client.build::<()>(Method::GET, "/v1/inbound", &q, None))
25            .await
26    }
27
28    /// Retrieve a single inbound email.
29    pub async fn get(&self, id: &str) -> Result<InboundEmail, Error> {
30        self.client
31            .request(self.client.build::<()>(
32                Method::GET,
33                &format!("/v1/inbound/{id}"),
34                &[],
35                None,
36            ))
37            .await
38    }
39
40    /// Get the inbound forwarding configuration.
41    pub async fn get_config(&self) -> Result<InboundConfig, Error> {
42        self.client
43            .request(self.client.build::<()>(
44                Method::GET,
45                "/v1/inbound/config",
46                &[],
47                None,
48            ))
49            .await
50    }
51
52    /// Update the inbound forwarding configuration.
53    pub async fn update_config(
54        &self,
55        params: UpdateInboundConfig,
56    ) -> Result<InboundConfig, Error> {
57        self.client
58            .request(self.client.build(
59                Method::PUT,
60                "/v1/inbound/config",
61                &[],
62                Some(&params),
63            ))
64            .await
65    }
66}
67
68/// One inbound email attachment.
69#[derive(Debug, Clone, Deserialize)]
70pub struct InboundEmailAttachment {
71    /// File name.
72    pub filename: String,
73    /// MIME type.
74    #[serde(rename = "contentType")]
75    pub content_type: String,
76    /// Size in bytes.
77    pub size: u64,
78    /// Optional inline content id.
79    #[serde(rename = "contentId", default)]
80    pub content_id: Option<String>,
81}
82
83/// Inbound email record.
84#[derive(Debug, Clone, Deserialize)]
85pub struct InboundEmail {
86    /// Inbound email id.
87    pub id: String,
88    /// From address.
89    pub from: String,
90    /// To addresses.
91    pub to: Vec<String>,
92    /// CC addresses.
93    #[serde(default)]
94    pub cc: Vec<String>,
95    /// Subject.
96    pub subject: Option<String>,
97    /// Plain-text body.
98    pub text: Option<String>,
99    /// HTML body.
100    pub html: Option<String>,
101    /// Raw headers.
102    pub headers: Option<HashMap<String, String>>,
103    /// Attachments.
104    #[serde(default)]
105    pub attachments: Vec<InboundEmailAttachment>,
106    /// Whether webhook delivery succeeded.
107    pub webhook_delivered: bool,
108    /// Received timestamp.
109    pub created_at: String,
110}
111
112/// Inbound forwarding configuration.
113#[derive(Debug, Clone, Deserialize)]
114pub struct InboundConfig {
115    /// Forwarding URL.
116    pub url: Option<String>,
117    /// HMAC signing secret.
118    pub secret: Option<String>,
119}
120
121/// Parameters for [`Inbound::update_config`].
122#[derive(Debug, Clone, Serialize)]
123pub struct UpdateInboundConfig {
124    /// Forwarding URL (or `None` to disable).
125    pub url: Option<String>,
126    /// Optional HMAC signing secret.
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub secret: Option<String>,
129}