oci_api/services/email/
client.rs1use async_trait::async_trait;
4
5use crate::client::Oci;
6use crate::error::{Error, Result};
7use crate::services::email::models::*;
8use crate::services::email::sender_trait::EmailSender;
9
10#[derive(Clone)]
12pub struct EmailDelivery {
13 oci_client: Oci,
15
16 submit_endpoint: String,
18}
19
20impl EmailDelivery {
21 pub async fn new(oci_client: Oci) -> Result<Self> {
28 let tenancy_id = oci_client.tenancy_id().to_string();
30 let region = oci_client.region().to_string();
31
32 let config =
34 Self::get_email_configuration_internal(&oci_client, &tenancy_id, ®ion).await?;
35
36 Ok(Self {
37 oci_client,
38 submit_endpoint: config.http_submit_endpoint,
39 })
40 }
41
42 async fn get_email_configuration_internal(
44 oci_client: &Oci,
45 compartment_id: &str,
46 region: &str,
47 ) -> Result<EmailConfiguration> {
48 let path = format!("/20170907/configuration?compartmentId={compartment_id}");
50 let host = format!("ctrl.email.{region}.oci.oraclecloud.com");
51 let url = format!("https://{host}{path}");
52
53 let (date_header, auth_header) = oci_client
55 .signer()
56 .sign_request("GET", &path, &host, None)?;
57
58 let response = oci_client
60 .client()
61 .get(&url)
62 .header("host", &host)
63 .header("date", &date_header)
64 .header("authorization", &auth_header)
65 .send()
66 .await?;
67
68 if !response.status().is_success() {
69 let status = response.status();
70 let body = response.text().await?;
71 return Err(Error::ApiError {
72 code: status.to_string(),
73 message: body,
74 });
75 }
76
77 response.json().await.map_err(Into::into)
78 }
79
80 pub async fn get_email_configuration(
85 &self,
86 compartment_id: impl Into<String>,
87 ) -> Result<EmailConfiguration> {
88 let compartment_id = compartment_id.into();
89 let region = self.oci_client.region().to_string();
90 Self::get_email_configuration_internal(&self.oci_client, &compartment_id, ®ion).await
91 }
92
93 pub async fn send(&self, email: Email) -> Result<SubmitEmailResponse> {
101 self.send_impl(email).await
102 }
103
104 async fn send_impl(&self, mut email: Email) -> Result<SubmitEmailResponse> {
106 let compartment_id = self.oci_client.compartment_id().to_string();
108
109 if email.sender.compartment_id.is_empty() {
111 email.sender.set_compartment_id(&compartment_id);
112 }
113
114 let path = "/20220926/actions/submitEmail";
116 let url = format!("https://{}{}", &self.submit_endpoint, path);
117
118 let body_json = serde_json::to_string(&email)?;
120
121 let body_sha256 = {
123 use base64::{Engine, engine::general_purpose};
124 use sha2::{Digest, Sha256};
125 let mut hasher = Sha256::new();
126 hasher.update(body_json.as_bytes());
127 let result = hasher.finalize();
128 general_purpose::STANDARD.encode(result)
129 };
130
131 let (date_header, auth_header) = self.oci_client.signer().sign_request(
133 "POST",
134 path,
135 &self.submit_endpoint,
136 Some(&body_json),
137 )?;
138
139 let response = self
141 .oci_client
142 .client()
143 .post(&url)
144 .header("host", &self.submit_endpoint)
145 .header("date", &date_header)
146 .header("authorization", &auth_header)
147 .header("content-type", "application/json")
148 .header("content-length", body_json.len().to_string())
149 .header("x-content-sha256", &body_sha256)
150 .body(body_json)
151 .send()
152 .await?;
153
154 if !response.status().is_success() {
155 let status = response.status();
156 let body = response.text().await?;
157 return Err(Error::ApiError {
158 code: status.to_string(),
159 message: body,
160 });
161 }
162
163 let submit_response: SubmitEmailResponse = response.json().await?;
164 Ok(submit_response)
165 }
166
167 pub async fn list_senders(
174 &self,
175 compartment_id: impl Into<String>,
176 lifecycle_state: Option<&str>,
177 email_address: Option<&str>,
178 ) -> Result<Vec<SenderSummary>> {
179 let compartment_id = compartment_id.into();
180
181 let mut query_params = vec![format!("compartmentId={}", compartment_id)];
183
184 if let Some(state) = lifecycle_state {
185 query_params.push(format!("lifecycleState={state}"));
186 }
187
188 if let Some(email) = email_address {
189 query_params.push(format!("emailAddress={email}"));
190 }
191
192 let query_string = query_params.join("&");
193 let path = format!("/20170907/senders?{query_string}");
194 let host = format!(
195 "ctrl.email.{}.oci.oraclecloud.com",
196 self.oci_client.region()
197 );
198 let url = format!("https://{host}{path}");
199
200 let (date_header, auth_header) = self
202 .oci_client
203 .signer()
204 .sign_request("GET", &path, &host, None)?;
205
206 let response = self
208 .oci_client
209 .client()
210 .get(&url)
211 .header("host", &host)
212 .header("date", &date_header)
213 .header("authorization", &auth_header)
214 .send()
215 .await?;
216
217 if !response.status().is_success() {
218 let status = response.status();
219 let body = response.text().await?;
220 return Err(Error::ApiError {
221 code: status.to_string(),
222 message: body,
223 });
224 }
225
226 let senders: Vec<SenderSummary> = response.json().await?;
227 Ok(senders)
228 }
229}
230
231#[async_trait]
232impl EmailSender for EmailDelivery {
233 async fn send(&self, email: Email) -> Result<SubmitEmailResponse> {
234 self.send_impl(email).await
235 }
236}