email_queue.rs 119 lignes · 3280 octets
use chrono::{DateTime, Utc};
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

/// EmailQueue entity model
///
/// Represents an email in the queue waiting to be sent.
/// Emails are queued asynchronously to avoid blocking HTTP requests.
///
/// # Email Lifecycle
///
/// 1. **Enqueue**: Email added to queue with status 'pending'
/// 2. **Processing**: Background task picks up pending emails
/// 3. **Sending**: Attempt to send via SMTP
/// 4. **Success**: Status set to 'sent', sent_at timestamp recorded
/// 5. **Failure**: Status set to 'failed' after max attempts, error_message recorded
///
/// # Retry Logic
///
/// - Failed emails are retried with exponential backoff
/// - Maximum 5 attempts before marking as failed
/// - Retry delay increases with each attempt
#[derive(Clone, Debug, Serialize, Deserialize, DeriveEntityModel)]
#[sea_orm(table_name = "email_queue")]
pub struct Model {
    /// Unique identifier for the email queue entry
    #[sea_orm(primary_key)]
    pub id: Uuid,

    /// Recipient email address
    pub to_email: String,

    /// Recipient name (optional)
    pub to_name: Option<String>,

    /// Sender email address
    pub from_email: String,

    /// Sender name (optional)
    pub from_name: Option<String>,

    /// Email subject
    pub subject: String,

    /// HTML body content
    pub body_html: String,

    /// Plain text body content
    pub body_text: String,

    /// Type of email (password_reset, email_validation, etc.)
    #[sea_orm(indexed)]
    pub email_type: String,

    /// Email status (pending, sent, failed)
    #[sea_orm(indexed)]
    pub status: String,

    /// Number of send attempts
    pub attempts: i32,

    /// Timestamp of last send attempt
    pub last_attempt_at: Option<DateTime<Utc>>,

    /// Timestamp when email was successfully sent
    pub sent_at: Option<DateTime<Utc>>,

    /// Error message if sending failed
    pub error_message: Option<String>,

    /// Last SMTP status code returned by server (if available)
    pub smtp_code: Option<String>,

    /// Last SMTP response message returned by server (if available)
    pub smtp_response: Option<String>,

    /// Creation timestamp
    #[sea_orm(indexed)]
    pub created_at: DateTime<Utc>,

    /// Last update timestamp
    pub updated_at: DateTime<Utc>,
}

/// SeaORM relations for the EmailQueue entity (none defined).
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}

impl ActiveModelBehavior for ActiveModel {}

impl Model {
    /// Check if the email can be retried
    ///
    /// # Returns
    ///
    /// `true` if the email has failed and hasn't exceeded max attempts, `false` otherwise
    pub fn can_retry(&self, max_attempts: u32) -> bool {
        self.status == "failed" && (self.attempts as u32) < max_attempts
    }

    /// Check if the email is pending
    ///
    /// # Returns
    ///
    /// `true` if the email status is 'pending', `false` otherwise
    pub fn is_pending(&self) -> bool {
        self.status == "pending"
    }

    /// Check if the email was successfully sent
    ///
    /// # Returns
    ///
    /// `true` if the email status is 'sent', `false` otherwise
    pub fn is_sent(&self) -> bool {
        self.status == "sent"
    }
}