use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Address {
pub email: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
}
impl Address {
pub fn new(email: impl Into<String>) -> Self {
Self {
email: email.into(),
name: None,
}
}
pub fn named(email: impl Into<String>, name: impl Into<String>) -> Self {
Self {
email: email.into(),
name: Some(name.into()),
}
}
}
impl From<&str> for Address {
fn from(s: &str) -> Self {
Address::new(s)
}
}
impl From<String> for Address {
fn from(s: String) -> Self {
Address::new(s)
}
}
impl From<(&str, &str)> for Address {
fn from((email, name): (&str, &str)) -> Self {
Address::named(email, name)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Attachment {
pub filename: String,
pub content_base64: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub content_type: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Page<T> {
pub items: Vec<T>,
pub total: u64,
pub page: u64,
pub limit: u64,
}
#[derive(Debug, Clone, Serialize)]
pub struct SendEmail {
#[serde(rename = "from_")]
pub from: Address,
pub to: Vec<Address>,
pub subject: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub html: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cc: Option<Vec<Address>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bcc: Option<Vec<Address>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reply_to: Option<Address>,
#[serde(skip_serializing_if = "Option::is_none")]
pub headers: Option<HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tags: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub send_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attachments: Option<Vec<Attachment>>,
}
impl SendEmail {
pub fn builder(
from: impl Into<Address>,
to: impl IntoAddressList,
subject: impl Into<String>,
) -> SendEmailBuilder {
SendEmailBuilder {
inner: SendEmail {
from: from.into(),
to: to.into_address_list(),
subject: subject.into(),
html: None,
text: None,
cc: None,
bcc: None,
reply_to: None,
headers: None,
tags: None,
send_at: None,
attachments: None,
},
}
}
}
pub trait IntoAddressList {
fn into_address_list(self) -> Vec<Address>;
}
impl IntoAddressList for Address {
fn into_address_list(self) -> Vec<Address> {
vec![self]
}
}
impl IntoAddressList for &str {
fn into_address_list(self) -> Vec<Address> {
vec![Address::new(self)]
}
}
impl IntoAddressList for String {
fn into_address_list(self) -> Vec<Address> {
vec![Address::new(self)]
}
}
impl<T: Into<Address>> IntoAddressList for Vec<T> {
fn into_address_list(self) -> Vec<Address> {
self.into_iter().map(Into::into).collect()
}
}
#[derive(Debug, Clone)]
pub struct SendEmailBuilder {
inner: SendEmail,
}
impl SendEmailBuilder {
pub fn html(mut self, html: impl Into<String>) -> Self {
self.inner.html = Some(html.into());
self
}
pub fn text(mut self, text: impl Into<String>) -> Self {
self.inner.text = Some(text.into());
self
}
pub fn cc(mut self, cc: impl IntoAddressList) -> Self {
self.inner.cc = Some(cc.into_address_list());
self
}
pub fn bcc(mut self, bcc: impl IntoAddressList) -> Self {
self.inner.bcc = Some(bcc.into_address_list());
self
}
pub fn reply_to(mut self, reply_to: impl Into<Address>) -> Self {
self.inner.reply_to = Some(reply_to.into());
self
}
pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
self.inner.headers = Some(headers);
self
}
pub fn tags(mut self, tags: Vec<String>) -> Self {
self.inner.tags = Some(tags);
self
}
pub fn send_at(mut self, send_at: impl Into<String>) -> Self {
self.inner.send_at = Some(send_at.into());
self
}
pub fn attachments(mut self, attachments: Vec<Attachment>) -> Self {
self.inner.attachments = Some(attachments);
self
}
pub fn build(self) -> SendEmail {
self.inner
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct SendEmailResponse {
pub id: String,
pub status: String,
pub message_id: Option<String>,
pub rejection_reason: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BatchItemResult {
pub id: Option<String>,
pub status: String,
pub rejection_reason: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BatchResponse {
pub total: u64,
pub sent: u64,
pub failed: u64,
pub results: Vec<BatchItemResult>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ValidationIssue {
pub field: String,
pub error: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ValidationUsage {
pub daily: u64,
pub daily_limit: u64,
pub monthly: u64,
pub monthly_limit: u64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ValidationResult {
pub valid: bool,
pub can_send: bool,
pub issues: Vec<ValidationIssue>,
pub plan: String,
pub usage: ValidationUsage,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Email {
pub id: String,
pub from_address: String,
pub to_addresses: Vec<String>,
pub subject: Option<String>,
pub status: String,
#[serde(default)]
pub source: Option<String>,
#[serde(default)]
pub opened_count: Option<u64>,
#[serde(default)]
pub clicked_count: Option<u64>,
#[serde(default)]
pub tags: Option<Vec<String>>,
#[serde(default)]
pub scheduled_at: Option<String>,
pub created_at: Option<String>,
#[serde(default)]
pub sent_at: Option<String>,
#[serde(default)]
pub delivered_at: Option<String>,
#[serde(default)]
pub retry_of_id: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct EmailEvent {
pub id: String,
pub event_type: String,
#[serde(default)]
pub metadata: Option<Value>,
pub created_at: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct EmailDetail {
#[serde(flatten)]
pub email: Email,
#[serde(default)]
pub cc_addresses: Option<Vec<String>>,
#[serde(default)]
pub bcc_addresses: Option<Vec<String>>,
#[serde(default)]
pub text_body: Option<String>,
#[serde(default)]
pub html_body: Option<String>,
#[serde(default)]
pub headers: Option<Value>,
#[serde(default)]
pub message_id: Option<String>,
#[serde(default)]
pub events: Vec<EmailEvent>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ScheduledEmail {
pub id: String,
pub from_address: String,
pub to_addresses: Vec<String>,
pub subject: Option<String>,
pub status: String,
#[serde(default)]
pub tags: Option<Vec<String>>,
#[serde(default)]
pub scheduled_at: Option<String>,
pub seconds_until_send: i64,
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct EmailSearchHit {
pub id: String,
pub from_address: String,
pub to_addresses: Vec<String>,
pub subject: Option<String>,
pub status: String,
#[serde(default)]
pub tags: Option<Vec<String>>,
#[serde(default)]
pub source: Option<String>,
pub created_at: Option<String>,
#[serde(default)]
pub delivered_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct IdStatus {
pub id: String,
pub status: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DomainListItem {
pub id: String,
pub name: String,
pub status: String,
pub created_at: Option<String>,
#[serde(default)]
pub platform_warning: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DnsRecord {
pub id: String,
pub record_type: String,
pub purpose: String,
pub host: String,
pub value: String,
pub is_verified: bool,
#[serde(default)]
pub last_checked_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Domain {
pub id: String,
pub name: String,
pub status: String,
pub dkim_selector: String,
#[serde(default)]
pub verified_at: Option<String>,
pub created_at: Option<String>,
pub dns_records: Vec<DnsRecord>,
#[serde(default)]
pub platform_warning: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DomainHealthCheck {
pub key: String,
pub label: String,
pub status: String,
pub detail: String,
#[serde(default)]
pub recommendation: Option<String>,
#[serde(default)]
pub record: Option<Value>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DomainHealthSummary {
pub ok: u64,
pub warn: u64,
pub error: u64,
pub info: u64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DomainHealth {
pub domain: String,
pub checks: Vec<DomainHealthCheck>,
pub summary: DomainHealthSummary,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DomainDiagnosis {
pub domain: String,
pub issues: Vec<Value>,
pub health_score: i64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DkimRotation {
pub dkim_record_host: String,
pub dkim_record_value: String,
pub domain: Domain,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DomainTransfer {
pub id: String,
pub domain_id: String,
#[serde(default)]
pub domain_name: Option<String>,
#[serde(default)]
pub source_label: Option<String>,
pub target_email: String,
pub status: String,
#[serde(default)]
pub note: Option<String>,
#[serde(default)]
pub cooloff_until: Option<String>,
pub initiated_at: String,
#[serde(default)]
pub accepted_at: Option<String>,
#[serde(default)]
pub completed_at: Option<String>,
pub expires_at: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DomainAvailability {
pub available: bool,
pub reason: Option<String>,
pub detail: Option<String>,
pub stale_tokens: Option<i64>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DomainCheck {
pub exists: bool,
pub verified: bool,
#[serde(default)]
pub status: Option<String>,
pub domain: String,
#[serde(default)]
pub id: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ContactList {
pub id: String,
pub name: String,
pub description: Option<String>,
pub icon_seed: Option<String>,
pub contact_count: u64,
pub created_at: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Contact {
pub id: String,
pub email: String,
pub name: Option<String>,
#[serde(default)]
pub metadata: Option<Value>,
pub created_at: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ContactListDetail {
#[serde(flatten)]
pub list: ContactList,
pub contacts: Vec<Contact>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct CreateList {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "icon_seed", skip_serializing_if = "Option::is_none")]
pub icon_seed: Option<String>,
}
impl CreateList {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
description: None,
icon_seed: None,
}
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn icon_seed(mut self, icon_seed: impl Into<String>) -> Self {
self.icon_seed = Some(icon_seed.into());
self
}
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct UpdateList {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "icon_seed", skip_serializing_if = "Option::is_none")]
pub icon_seed: Option<String>,
}
impl UpdateList {
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn icon_seed(mut self, icon_seed: impl Into<String>) -> Self {
self.icon_seed = Some(icon_seed.into());
self
}
}
#[derive(Debug, Clone, Serialize)]
pub struct AddContact {
pub email: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<Value>,
}
impl AddContact {
pub fn new(email: impl Into<String>) -> Self {
Self {
email: email.into(),
name: None,
metadata: None,
}
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn metadata(mut self, metadata: Value) -> Self {
self.metadata = Some(metadata);
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct CsvImportResult {
pub imported: u64,
pub skipped: u64,
pub errors: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct BulkSend {
pub contact_list_id: String,
pub sender_address_id: String,
pub subject: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub html: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tags: Option<Vec<String>>,
}
impl BulkSend {
pub fn new(sender_address_id: impl Into<String>, subject: impl Into<String>) -> Self {
Self {
contact_list_id: String::new(),
sender_address_id: sender_address_id.into(),
subject: subject.into(),
html: None,
text: None,
tags: None,
}
}
pub fn html(mut self, html: impl Into<String>) -> Self {
self.html = Some(html.into());
self
}
pub fn text(mut self, text: impl Into<String>) -> Self {
self.text = Some(text.into());
self
}
pub fn tags(mut self, tags: Vec<String>) -> Self {
self.tags = Some(tags);
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct BulkSendResult {
pub queued: u64,
pub skipped: u64,
pub errors: Vec<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Suppression {
pub id: String,
pub email_address: String,
pub reason: String,
#[serde(default)]
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct AddSuppression {
#[serde(rename = "email_address")]
pub email: String,
pub reason: String,
}
impl AddSuppression {
pub fn new(email: impl Into<String>) -> Self {
Self {
email: email.into(),
reason: "manual".to_string(),
}
}
pub fn reason(mut self, reason: impl Into<String>) -> Self {
self.reason = reason.into();
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct BulkSuppressionResult {
pub added: u64,
pub skipped: u64,
pub total_processed: u64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Template {
pub id: String,
pub name: String,
pub subject: Option<String>,
pub html_body: Option<String>,
pub text_body: Option<String>,
#[serde(default)]
pub variables: Option<Vec<String>>,
#[serde(default)]
pub blocks_json: Option<Value>,
pub created_at: String,
pub updated_at: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateTemplate {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub subject: Option<String>,
#[serde(rename = "html_body", skip_serializing_if = "Option::is_none")]
pub html: Option<String>,
#[serde(rename = "text_body", skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(rename = "blocks_json", skip_serializing_if = "Option::is_none")]
pub blocks_json: Option<Value>,
}
impl CreateTemplate {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
subject: None,
html: None,
text: None,
blocks_json: None,
}
}
pub fn subject(mut self, subject: impl Into<String>) -> Self {
self.subject = Some(subject.into());
self
}
pub fn html(mut self, html: impl Into<String>) -> Self {
self.html = Some(html.into());
self
}
pub fn text(mut self, text: impl Into<String>) -> Self {
self.text = Some(text.into());
self
}
pub fn blocks_json(mut self, blocks_json: Value) -> Self {
self.blocks_json = Some(blocks_json);
self
}
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct UpdateTemplate {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub subject: Option<String>,
#[serde(rename = "html_body", skip_serializing_if = "Option::is_none")]
pub html: Option<String>,
#[serde(rename = "text_body", skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(rename = "blocks_json", skip_serializing_if = "Option::is_none")]
pub blocks_json: Option<Value>,
}
impl UpdateTemplate {
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn subject(mut self, subject: impl Into<String>) -> Self {
self.subject = Some(subject.into());
self
}
pub fn html(mut self, html: impl Into<String>) -> Self {
self.html = Some(html.into());
self
}
pub fn text(mut self, text: impl Into<String>) -> Self {
self.text = Some(text.into());
self
}
pub fn blocks_json(mut self, blocks_json: Value) -> Self {
self.blocks_json = Some(blocks_json);
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct Webhook {
pub id: String,
pub url: String,
pub events: Vec<String>,
pub secret: String,
pub is_active: bool,
pub created_at: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct CreateWebhook {
pub url: String,
pub events: Vec<String>,
}
impl CreateWebhook {
pub fn new(url: impl Into<String>, events: Vec<String>) -> Self {
Self {
url: url.into(),
events,
}
}
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct UpdateWebhook {
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub events: Option<Vec<String>>,
#[serde(rename = "is_active", skip_serializing_if = "Option::is_none")]
pub is_active: Option<bool>,
}
impl UpdateWebhook {
pub fn url(mut self, url: impl Into<String>) -> Self {
self.url = Some(url.into());
self
}
pub fn events(mut self, events: Vec<String>) -> Self {
self.events = Some(events);
self
}
pub fn is_active(mut self, is_active: bool) -> Self {
self.is_active = Some(is_active);
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct WebhookTestResult {
pub queued: bool,
pub url: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WebhookDelivery {
pub id: String,
pub webhook_id: String,
pub event_type: Option<String>,
pub status: String,
pub response_status: Option<i64>,
pub attempt: i64,
pub next_retry_at: Option<String>,
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WebhookDeliveryDetail {
#[serde(flatten)]
pub delivery: WebhookDelivery,
pub payload: Value,
pub response_body: Option<String>,
pub endpoint_url: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct TransferDomain {
pub target_email: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
}
impl TransferDomain {
pub fn new(target_email: impl Into<String>) -> Self {
Self {
target_email: target_email.into(),
note: None,
}
}
pub fn note(mut self, note: impl Into<String>) -> Self {
self.note = Some(note.into());
self
}
}