sentd 1.0.0

Official Rust SDK for the SENTD Email API
Documentation
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Request to send an email
#[derive(Debug, Clone, Serialize, Default)]
pub struct SendEmailRequest {
    pub from: String,
    pub to: Vec<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 cc: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub bcc: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reply_to: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub attachments: Option<Vec<Attachment>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub headers: Option<HashMap<String, String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<HashMap<String, serde_json::Value>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tracking: Option<TrackingOptions>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub routing: Option<RoutingOptions>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub send_at: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub send_at_timezone: Option<String>,
}

/// Email attachment
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Attachment {
    pub filename: String,
    pub content: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub content_type: Option<String>,
}

/// Tracking options
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrackingOptions {
    pub opens: bool,
    pub clicks: bool,
}

/// Routing options
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoutingOptions {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub provider: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub priority: Option<String>,
}

/// Response from sending an email
#[derive(Debug, Clone, Deserialize)]
pub struct SendEmailResponse {
    pub data: SendEmailData,
}

#[derive(Debug, Clone, Deserialize)]
pub struct SendEmailData {
    pub id: String,
}

/// Email record
#[derive(Debug, Clone, Deserialize)]
pub struct Email {
    pub id: String,
    pub from: String,
    pub to: Vec<String>,
    pub subject: String,
    pub status: String,
    pub provider: Option<String>,
    pub metadata: Option<HashMap<String, serde_json::Value>>,
    pub created_at: String,
    pub sent_at: Option<String>,
    pub delivered_at: Option<String>,
}

/// Response from listing emails
#[derive(Debug, Clone, Deserialize)]
pub struct ListEmailsResponse {
    pub data: Vec<Email>,
    pub total: i64,
}

/// Response from getting an email
#[derive(Debug, Clone, Deserialize)]
pub struct GetEmailResponse {
    pub data: Email,
}

/// Request to send batch emails
#[derive(Debug, Clone, Serialize, Default)]
pub struct SendBatchRequest {
    pub emails: Vec<BatchEmail>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub from: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub subject: Option<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 template_id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub template_data: Option<HashMap<String, serde_json::Value>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reply_to: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub attachments: Option<Vec<Attachment>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tracking: Option<TrackingOptions>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub routing: Option<RoutingOptions>,
}

/// Single email in a batch
#[derive(Debug, Clone, Serialize, Default)]
pub struct BatchEmail {
    pub to: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub data: Option<HashMap<String, serde_json::Value>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub send_at: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub send_at_timezone: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<HashMap<String, serde_json::Value>>,
}

/// Response from sending batch
#[derive(Debug, Clone, Deserialize)]
pub struct SendBatchResponse {
    pub data: SendBatchData,
}

#[derive(Debug, Clone, Deserialize)]
pub struct SendBatchData {
    pub batch_id: String,
    pub email_ids: Vec<String>,
    pub accepted: i64,
    pub rejected: i64,
}

/// Email template
#[derive(Debug, Clone, Deserialize)]
pub struct Template {
    pub id: String,
    pub name: String,
    pub description: Option<String>,
    pub subject_template: String,
    pub html_template: String,
    pub text_template: Option<String>,
    pub variables: Option<Vec<TemplateVariable>>,
    pub default_from: Option<String>,
    pub reply_to: Option<String>,
    pub created_at: String,
    pub updated_at: String,
}

/// Template variable definition
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplateVariable {
    pub name: String,
    pub description: Option<String>,
    pub default_value: Option<String>,
    pub required: bool,
}

/// Request to create a template
#[derive(Debug, Clone, Serialize)]
pub struct CreateTemplateRequest {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    pub subject_template: String,
    pub html_template: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub text_template: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub variables: Option<Vec<TemplateVariable>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub default_from: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reply_to: Option<String>,
}

/// Response containing a template
#[derive(Debug, Clone, Deserialize)]
pub struct TemplateResponse {
    pub data: Template,
}

/// Response from listing templates
#[derive(Debug, Clone, Deserialize)]
pub struct ListTemplatesResponse {
    pub data: Vec<Template>,
}

/// Response from previewing a template
#[derive(Debug, Clone, Deserialize)]
pub struct PreviewTemplateResponse {
    pub data: PreviewTemplateData,
}

#[derive(Debug, Clone, Deserialize)]
pub struct PreviewTemplateData {
    pub subject: String,
    pub html: String,
    pub text: Option<String>,
}

/// Sending domain
#[derive(Debug, Clone, Deserialize)]
pub struct Domain {
    pub id: String,
    pub domain: String,
    pub status: String,
    pub records: Option<Vec<DomainRecord>>,
    pub created_at: String,
    pub verified_at: Option<String>,
}

/// DNS record for domain verification
#[derive(Debug, Clone, Deserialize)]
pub struct DomainRecord {
    pub r#type: String,
    pub name: String,
    pub value: String,
    pub priority: Option<i32>,
    pub status: String,
}

/// Response containing a domain
#[derive(Debug, Clone, Deserialize)]
pub struct DomainResponse {
    pub data: Domain,
}

/// Response from listing domains
#[derive(Debug, Clone, Deserialize)]
pub struct ListDomainsResponse {
    pub data: Vec<Domain>,
}

/// Response from verifying a domain
#[derive(Debug, Clone, Deserialize)]
pub struct VerifyDomainResponse {
    pub data: VerifyDomainData,
}

#[derive(Debug, Clone, Deserialize)]
pub struct VerifyDomainData {
    pub verified: bool,
    pub records: Vec<DomainRecord>,
}

/// Webhook endpoint
#[derive(Debug, Clone, Deserialize)]
pub struct Webhook {
    pub id: String,
    pub url: String,
    pub events: Vec<String>,
    pub active: bool,
    pub secret: Option<String>,
    pub created_at: String,
    pub updated_at: String,
}

/// Request to create a webhook
#[derive(Debug, Clone, Serialize)]
pub struct CreateWebhookRequest {
    pub url: String,
    pub events: Vec<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub active: Option<bool>,
}

/// Response containing a webhook
#[derive(Debug, Clone, Deserialize)]
pub struct WebhookResponse {
    pub data: Webhook,
}

/// Response from listing webhooks
#[derive(Debug, Clone, Deserialize)]
pub struct ListWebhooksResponse {
    pub data: Vec<Webhook>,
}

/// Analytics data
#[derive(Debug, Clone, Deserialize)]
pub struct AnalyticsResponse {
    pub data: AnalyticsData,
}

#[derive(Debug, Clone, Deserialize)]
pub struct AnalyticsData {
    pub total_sent: i64,
    pub total_delivered: i64,
    pub total_opened: i64,
    pub total_clicked: i64,
    pub total_bounced: i64,
    pub total_failed: i64,
    pub delivery_rate: f64,
    pub open_rate: f64,
    pub click_rate: f64,
    pub bounce_rate: f64,
    pub daily: Option<Vec<DailyStats>>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct DailyStats {
    pub date: String,
    pub sent: i64,
    pub delivered: i64,
    pub opened: i64,
    pub clicked: i64,
    pub bounced: i64,
    pub failed: i64,
}

/// Generic success response
#[derive(Debug, Clone, Deserialize)]
pub struct SuccessResponse {
    pub success: bool,
}