first commit 🍻

This commit is contained in:
2026-04-29 18:31:37 -05:00
commit 394794b0be
11 changed files with 2327 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
use crate::email::{Email, EmailAddress, EmailContent};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use std::collections::BTreeMap;
#[derive(Clone, Debug, Serialize)]
pub(crate) struct WireEmail {
to: WireRecipients,
#[serde(skip_serializing_if = "Option::is_none")]
subject: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
body: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
template: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
from: Option<WireEmailAddress>,
#[serde(skip_serializing_if = "Map::is_empty", default)]
data: Map<String, Value>,
#[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
headers: BTreeMap<String, String>,
#[serde(rename = "reply", skip_serializing_if = "Option::is_none")]
reply: Option<String>,
}
impl From<&Email> for WireEmail {
fn from(value: &Email) -> Self {
let (subject, body, template) = match &value.content {
EmailContent::Html { subject, body } => {
(Some(subject.clone()), Some(body.clone()), None)
}
EmailContent::Template { template_id } => (None, None, Some(template_id.clone())),
};
Self {
to: WireRecipients::from(value.recipients()),
subject,
body,
template,
from: value.from.as_ref().map(WireEmailAddress::from),
data: value.data.clone(),
headers: value.headers.clone(),
reply: value.reply_to.as_ref().map(|a| a.email.clone()),
}
}
}
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
enum WireRecipients {
One(WireEmailAddress),
Many(Vec<WireEmailAddress>),
}
impl From<&[EmailAddress]> for WireRecipients {
fn from(value: &[EmailAddress]) -> Self {
match value {
[only] => Self::One(WireEmailAddress::from(only)),
many => Self::Many(many.iter().map(WireEmailAddress::from).collect()),
}
}
}
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
enum WireEmailAddress {
Plain(String),
Named { name: String, email: String },
}
impl From<&EmailAddress> for WireEmailAddress {
fn from(value: &EmailAddress) -> Self {
match &value.name {
Some(name) => Self::Named {
name: name.clone(),
email: value.email.clone(),
},
None => Self::Plain(value.email.clone()),
}
}
}
#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WireSendResponse {
pub(crate) success: bool,
pub(crate) data: WireSendResponseData,
}
#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WireSendResponseData {
pub(crate) emails: Vec<WireDeliveredEmail>,
pub(crate) timestamp: String,
}
#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WireDeliveredEmail {
pub(crate) contact: WireContact,
pub(crate) email: String,
}
#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WireContact {
pub(crate) id: String,
pub(crate) email: String,
}
#[derive(Clone, Debug, Deserialize)]
pub(crate) struct WireApiError {
pub(crate) code: i64,
pub(crate) error: String,
pub(crate) message: String,
}