#[cfg(feature = "host-only")]
mod sqlite;
#[cfg(feature = "host-only")]
pub use sqlite::EmailBind;
#[derive(Debug, thiserror::Error)]
pub enum SendEmailError {
#[error("email not allowed: {0}")]
EmailNotAllowed(String),
}
#[derive(Debug, thiserror::Error)]
pub enum CancelEmailError {
#[error("unknown handle")]
UnknownHandle,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Email {
pub from: EmailAddress,
pub to: smallvec::SmallVec<EmailAddress, 1>,
pub reply_to: Option<smallvec::SmallVec<EmailAddress, 1>>,
pub cc: smallvec::SmallVec<EmailAddress, 0>,
pub bcc: smallvec::SmallVec<EmailAddress, 0>,
pub mkind: String,
pub content: EmailContent,
}
impl Email {
pub fn merge_context(
&self,
context: Option<serde_json::Map<String, serde_json::Value>>,
) -> Result<serde_json::Map<String, serde_json::Value>, serde_json::Error> {
let mut context = context.unwrap_or_default();
context.insert("from".to_string(), serde_json::to_value(&self.from)?);
context.insert("to".to_string(), serde_json::to_value(&self.to)?);
if let Some(ref reply_to) = self.reply_to {
context.insert("reply_to".to_string(), serde_json::to_value(reply_to)?);
}
context.insert("cc".to_string(), serde_json::to_value(&self.cc)?);
context.insert("bcc".to_string(), serde_json::to_value(&self.bcc)?);
context.insert("mkind".to_string(), serde_json::to_value(&self.mkind)?);
Ok(context)
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum EmailContent {
Rendered(RenderedEmail),
FromMKind {
context: Option<serde_json::Map<String, serde_json::Value>>,
},
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct RenderedEmail {
subject: String,
#[serde(rename = "html")]
body_html: String,
#[serde(rename = "text")]
body_text: String,
}
impl Default for EmailContent {
fn default() -> Self {
EmailContent::FromMKind { context: None }
}
}
impl Email {
pub fn new(from: EmailAddress, to: EmailAddress, mkind: &str, content: EmailContent) -> Self {
Email {
from,
to: smallvec::smallvec![to],
reply_to: None,
cc: smallvec::smallvec![],
bcc: smallvec::smallvec![],
mkind: mkind.to_string(),
content,
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct EmailAddress {
pub name: Option<String>,
pub email: String,
}
impl std::fmt::Display for EmailAddress {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let str = match self.name {
Some(ref name) => format!("{name} <{}>", self.email),
None => self.email.to_string(),
};
write!(f, "{}", str)
}
}
impl From<(String, String)> for EmailAddress {
fn from((name, email): (String, String)) -> Self {
EmailAddress {
name: Some(name),
email,
}
}
}
impl From<String> for EmailAddress {
fn from(email: String) -> Self {
let email = email.trim().to_string();
if let Some(i) = email.find('<') {
let name = email[..i].to_string();
let email = email[i + 1..].to_string();
EmailAddress {
name: Some(name),
email,
}
} else {
EmailAddress { name: None, email }
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct EmailHandle(String);
#[cfg(feature = "host-only")]
impl EmailHandle {
#[doc(hidden)]
pub fn new(handle: String) -> Self {
Self(handle)
}
#[doc(hidden)]
pub fn inner(&self) -> &str {
&self.0
}
}