use super::RequestObject;
use names::Generator;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Message {
pub from: NameAndEmail,
pub sender: Option<NameAndEmail>,
pub to: Option<Vec<NameAndEmail>>,
pub cc: Option<Vec<NameAndEmail>>,
pub bcc: Option<Vec<NameAndEmail>>,
pub reply_to: Option<NameAndEmail>,
pub subject: Option<String>,
pub text_part: Option<String>,
pub html_part: Option<String>,
pub template_id: Option<u64>,
pub template_language: Option<bool>,
pub template_error_reporting: Option<NameAndEmail>,
pub template_error_deliver: Option<bool>,
pub attachments: Option<Vec<Attachment>>,
pub inline_attachments: Option<Vec<Attachment>>,
pub priority: Option<u8>,
pub custom_campaign: Option<String>,
pub deduplicate_campaign: Option<bool>,
pub track_opens: Option<Track>,
pub track_clicks: Option<Track>,
#[serde(rename = "CustomID")]
pub custom_id: Option<String>,
pub event_payload: Option<String>,
#[serde(rename = "URLTags")]
pub url_tags: Option<String>,
pub headers: Option<HashMap<String, String>>,
pub variables: Option<HashMap<String, String>>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct SimpleMessage {
pub from_email: String,
pub from_name: String,
pub sender: Option<bool>,
pub recipients: Vec<NameAndEmail>,
pub to: Option<String>,
pub cc: Option<String>,
pub bcc: Option<String>,
pub subject: Option<String>,
#[serde(rename = "Text-part")]
pub text_part: Option<String>,
#[serde(rename = "Html-part")]
pub html_part: Option<String>,
pub attachments: Option<Vec<Attachment>>,
pub inline_attachments: Option<Vec<Attachment>>,
pub event_payload: Option<String>,
pub vars: Option<String>,
}
impl RequestObject for SimpleMessage {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[derive(Debug, Default)]
pub struct MessageBuilder {
pub from: Option<NameAndEmail>,
pub sender: Option<NameAndEmail>,
pub to: Option<Vec<NameAndEmail>>,
pub cc: Option<Vec<NameAndEmail>>,
pub bcc: Option<Vec<NameAndEmail>>,
pub reply_to: Option<NameAndEmail>,
pub subject: Option<String>,
pub text_part: Option<String>,
pub html_part: Option<String>,
pub template_id: Option<u64>,
pub template_language: Option<bool>,
pub template_error_reporting: Option<NameAndEmail>,
pub template_error_deliver: Option<bool>,
pub attachments: Option<Vec<Attachment>>,
pub inline_attachments: Option<Vec<Attachment>>,
pub priority: Option<u8>,
pub custom_campaign: Option<String>,
pub deduplicate_campaign: Option<bool>,
pub track_opens: Option<Track>,
pub track_clicks: Option<Track>,
pub custom_id: Option<String>,
pub event_payload: Option<String>,
pub url_tags: Option<String>,
pub headers: Option<HashMap<String, String>>,
pub variables: Option<HashMap<String, String>>,
}
impl MessageBuilder {
pub fn with_from(mut self, email: &str, name: Option<&str>) -> Self {
self.from = Some(NameAndEmail::new(email, name));
self
}
pub fn with_to(mut self, email: &str, name: Option<&str>) -> Self {
self.to = Some(Vec::from([
NameAndEmail::new(email, name),
NameAndEmail::new(email, name),
]));
self
}
pub fn with_text_body(mut self, body: &str) -> Self {
self.text_part = Some(body.to_string());
self
}
pub fn with_subject(mut self, subject: &str) -> Self {
self.subject = Some(subject.to_string());
self
}
pub fn with_html_body(mut self, body: &str) -> Self {
self.html_part = Some(body.to_string());
self
}
pub fn build(self) -> Message {
Message {
from: self.from.unwrap_or_default(),
sender: self.sender,
to: self.to,
cc: self.cc,
bcc: self.bcc,
reply_to: self.reply_to,
subject: self.subject,
text_part: self.text_part,
html_part: self.html_part,
template_id: self.template_id,
template_language: self.template_language,
template_error_reporting: self.template_error_reporting,
template_error_deliver: self.template_error_deliver,
attachments: self.attachments,
inline_attachments: self.inline_attachments,
priority: self.priority,
custom_campaign: self.custom_campaign,
deduplicate_campaign: self.deduplicate_campaign,
track_opens: self.track_opens,
track_clicks: self.track_clicks,
custom_id: self.custom_id,
event_payload: self.event_payload,
url_tags: self.url_tags,
headers: self.headers,
variables: self.variables,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct MessageProperty {
pub from: Option<NameAndEmail>,
pub sender: Option<NameAndEmail>,
pub cc: Option<Vec<NameAndEmail>>,
pub bcc: Option<Vec<NameAndEmail>>,
pub reply_to: Option<NameAndEmail>,
pub subject: Option<String>,
pub text_part: Option<String>,
pub html_part: Option<String>,
pub template_id: Option<u64>,
pub template_language: Option<bool>,
pub template_error_reporting: Option<NameAndEmail>,
pub template_error_deliver: Option<bool>,
pub attachments: Option<Vec<Attachment>>,
pub inline_attachments: Option<Vec<Attachment>>,
pub priority: Option<u8>,
pub custom_campaign: Option<String>,
pub deduplicate_campaign: Option<bool>,
pub track_opens: Option<Track>,
pub track_clicks: Option<Track>,
#[serde(rename = "CustomID")]
pub custom_id: Option<String>,
pub event_payload: Option<String>,
#[serde(rename = "URLTags")]
pub url_tags: Option<String>,
pub headers: Option<HashMap<String, String>>,
pub variables: Option<HashMap<String, String>>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct NameAndEmail {
pub email: String,
pub name: Option<String>,
pub vars: Option<String>,
}
impl Default for NameAndEmail {
fn default() -> Self {
let rand_name = Generator::default().next().unwrap();
NameAndEmail {
email: format!("{}@mail.com", rand_name.clone()),
name: Some(rand_name.replace(&rand_name, "-")),
vars: None,
}
}
}
impl NameAndEmail {
pub fn new(email: &str, name: Option<&str>) -> Self {
NameAndEmail {
email: email.into(),
name: name.map(str::to_string),
vars: None,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Attachment {
pub filename: String,
pub content_type: String,
pub base_64_content: String,
}
#[derive(Clone, Debug, Default, Serialize, PartialEq, Deserialize)]
pub enum Track {
#[default]
#[serde(rename = "account_default")]
AccountDefault,
#[serde(rename = "disabled")]
Disabled,
#[serde(rename = "enabled")]
Enabled,
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use rstest::*;
#[rstest]
fn message_builds() {
let test_email = "test@mail.com";
let name = Some("name");
let body = "a test body";
let subject = "a test subject";
let message = MessageBuilder::default()
.with_subject(subject)
.with_from(test_email, name)
.with_to(test_email, name)
.with_text_body(body)
.with_html_body(body)
.build();
assert_eq!(message.from.email, test_email);
assert_eq!(message.from.name.as_deref(), name);
assert_eq!(message.text_part.as_deref(), Some(body));
assert_eq!(message.html_part.as_deref(), Some(body));
assert_eq!(message.subject.as_deref(), Some(subject));
}
}