Skip to content

مزودو البريد الإلكتروني

يدعم FORGE إرسال رسائل البريد الإلكتروني التعاملية عبر drivers مزودين متعددة. يتعامل نظام البريد الإلكتروني مع التحقق من الحساب وإعادة تعيين كلمة المرور والإشعارات وأي بريد إلكتروني مخصص يحتاج تطبيقك لإرساله.

سمة EmailProvider

جميع drivers البريد الإلكتروني تُنفّذ سمة EmailProvider:

rust
#[async_trait]
pub trait EmailProvider: Send + Sync {
    /// Send a structured email message
    async fn send(&self, message: EmailMessage) -> Result<EmailResult, EmailError>;

    /// Send a templated email with dynamic data
    async fn send_template(
        &self,
        to: &str,
        template: &str,
        data: &serde_json::Value,
    ) -> Result<EmailResult, EmailError>;

    /// Validate email address format and optionally check deliverability
    async fn validate_email(&self, email: &str) -> Result<bool, EmailError>;
}

بنية EmailMessage

توفر بنية EmailMessage تحكماً كاملاً في تكوين البريد الإلكتروني:

rust
pub struct EmailMessage {
    /// Recipient email address(es)
    pub to: Vec<String>,
    /// Carbon copy recipients
    pub cc: Vec<String>,
    /// Blind carbon copy recipients
    pub bcc: Vec<String>,
    /// Email subject line
    pub subject: String,
    /// Plain text content (fallback for non-HTML clients)
    pub body_text: Option<String>,
    /// HTML content
    pub body_html: Option<String>,
    /// File attachments
    pub attachments: Vec<EmailAttachment>,
    /// Reply-to address (overrides default from address)
    pub reply_to: Option<String>,
}

pub struct EmailAttachment {
    /// Filename as it appears in the email
    pub filename: String,
    /// MIME type (e.g., "application/pdf")
    pub content_type: String,
    /// Raw file bytes
    pub data: Vec<u8>,
}

بنية EmailResult

كل عملية إرسال تُرجع EmailResult تؤكد التسليم:

rust
pub struct EmailResult {
    /// Unique message ID from the provider
    pub message_id: String,
    /// Delivery status
    pub status: EmailStatus,
}

pub enum EmailStatus {
    /// Message accepted by provider for delivery
    Queued,
    /// Message reached recipient's mail server
    Delivered,
    /// Delivery failed
    Failed(String),
}

الـ Drivers المتاحة

SMTP (الافتراضي)

تسليم البريد الإلكتروني عبر SMTP القياسي. هذا هو الـ driver الافتراضي ولا يتطلب تثبيتاً إضافياً. يعمل مع أي خادم SMTP قياسي بما في ذلك Gmail و Outlook و Amazon SES relay وخوادم التطوير المحلية مثل Mailhog.

الإعدادات:

الإعدادالنوعالافتراضيالوصف
email_hoststring--اسم مضيف خادم SMTP
email_portnumber587منفذ خادم SMTP
email_usernamestring--اسم مستخدم مصادقة SMTP
email_passwordencrypted--كلمة مرور مصادقة SMTP
email_encryptionstring"tls"طريقة التشفير: tls، ssl، أو none
email_from_addressstring--عنوان بريد المُرسل الافتراضي
email_from_namestring--اسم عرض المُرسل الافتراضي

نصيحة

SMTP هو الـ driver الافتراضي ويعمل مباشرة. للتطوير المحلي، استخدم Mailhog مع email_host: localhost، email_port: 1025، و email_encryption: none لالتقاط جميع رسائل البريد الصادرة بدون تسليمها فعلياً.

منافذ SMTP الشائعة
المنفذالبروتوكولحالة الاستخدام
25SMTPترحيل خادم إلى خادم (غالباً محظور من ISPs)
465SMTPSSSL/TLS ضمني
587SMTPإرسال مع STARTTLS (موصى به)
1025SMTPMailhog / التطوير المحلي

SendGrid

تسليم البريد الإلكتروني السحابي عبر SendGrid API. يوفر SendGrid إرسالاً عالي الحجم وتحليلات التسليم وإدارة القوالب من خلال لوحة التحكم.

التثبيت:

bash
forge provider:add email:sendgrid

الإعدادات:

الإعدادالنوعالوصف
sendgrid_api_keyencryptedSendGrid API Key
email_from_addressstringعنوان بريد المُرسل المُحقق
email_from_namestringاسم عرض المُرسل الافتراضي

الميزات:

  • رسائل البريد التعاملية -- إرسال عالي قابلية التسليم مُحسّن للرسائل المُولّدة من التطبيق
  • إدارة القوالب -- إنشاء وإدارة قوالب البريد في لوحة تحكم SendGrid، ثم الإشارة إليها بالمعرّف
  • تتبع التسليم -- حالة التسليم في الوقت الفعلي ومعدلات الفتح وتتبع النقرات
  • Webhooks -- استقبال ردود الاتصال لأحداث التسليم (delivered، bounced، opened، clicked)

تحذير

يتطلب SendGrid التحقق من المُرسل. تأكد من التحقق من email_from_address في حساب SendGrid قبل الإرسال. سيتم رفض المُرسلين غير المُحققين.

Mailgun

تسليم البريد الإلكتروني عبر Mailgun API.

التثبيت:

bash
forge provider:add email:mailgun

الإعدادات:

الإعدادالنوعالوصف
mailgun_api_keyencryptedMailgun API Key
mailgun_domainstringنطاق الإرسال في Mailgun
mailgun_regionstringمنطقة API: us أو eu
email_from_addressstringعنوان المُرسل الافتراضي
email_from_namestringاسم عرض المُرسل الافتراضي

Amazon SES

تسليم البريد الإلكتروني عبر Amazon Simple Email Service.

التثبيت:

bash
forge provider:add email:ses

الإعدادات:

الإعدادالنوعالوصف
ses_access_keyencryptedAWS Access Key ID
ses_secret_keyencryptedAWS Secret Access Key
ses_regionstringمنطقة AWS (مثل us-east-1)
email_from_addressstringعنوان المُرسل المُحقق
email_from_namestringاسم عرض المُرسل الافتراضي

تحذير

يبدأ Amazon SES في وضع sandbox، الذي يسمح فقط بالإرسال إلى عناوين بريد إلكتروني مُحققة. اطلب وصول الإنتاج من خلال وحدة تحكم AWS للإرسال بدون قيود.

الاستخدام

إنشاء المزود

يُنشئ المصنع الـ driver الصحيح بناءً على إعداداتك:

rust
use crate::services::email::EmailFactory;

let email = EmailFactory::create(&settings).await?;

إرسال بريد إلكتروني عادي

rust
let message = EmailMessage {
    to: vec!["user@example.com".to_string()],
    cc: vec![],
    bcc: vec![],
    subject: "مرحباً بك في تطبيقنا".to_string(),
    body_text: Some("شكراً للتسجيل!".to_string()),
    body_html: Some("<h1>مرحباً!</h1><p>شكراً للتسجيل.</p>".to_string()),
    attachments: vec![],
    reply_to: None,
};

let result = email.send(message).await?;
println!("Sent with message ID: {}", result.message_id);

الإرسال مع مرفقات

rust
let pdf_bytes = std::fs::read("invoice.pdf")?;

let message = EmailMessage {
    to: vec!["billing@example.com".to_string()],
    cc: vec!["accounting@example.com".to_string()],
    bcc: vec![],
    subject: "فاتورة #1234".to_string(),
    body_text: Some("يرجى الاطلاع على الفاتورة المرفقة.".to_string()),
    body_html: Some("<p>يرجى الاطلاع على الفاتورة المرفقة.</p>".to_string()),
    attachments: vec![
        EmailAttachment {
            filename: "invoice-1234.pdf".to_string(),
            content_type: "application/pdf".to_string(),
            data: pdf_bytes,
        }
    ],
    reply_to: Some("billing@mycompany.com".to_string()),
};

let result = email.send(message).await?;

إرسال بريد إلكتروني بقالب

rust
use serde_json::json;

let result = email.send_template(
    "user@example.com",
    "welcome",
    &json!({
        "name": "أحمد علي",
        "app_name": "تطبيقي",
        "verification_url": "https://example.com/verify?token=abc123"
    })
).await?;

نصيحة

رسائل البريد الإلكتروني المبنية على القوالب موصى بها لجميع الرسائل الموجهة للمستخدمين. تُبقي محتوى البريد الإلكتروني منفصلاً عن منطق التطبيق وتسمح لغير المطورين بتعديل نص البريد من خلال لوحة الإدارة أو لوحة تحكم المزود.

التحقق من عنوان بريد إلكتروني

rust
let is_valid = email.validate_email("user@example.com").await?;

if !is_valid {
    return Err(AppError::validation("عنوان بريد إلكتروني غير صالح"));
}

الإعدادات عبر الإدارة

تُدار إعدادات البريد الإلكتروني من خلال صفحة الإعدادات في الإدارة تحت مجموعة البريد الإلكتروني:

الإعدادات > البريد الإلكتروني
┌──────────────────────────────────────────────────┐
│  الـ Driver:       [SMTP             v]          │
│  المضيف:          [smtp.example.com   ]         │
│  المنفذ:          [587                ]         │
│  اسم المستخدم:    [noreply@example.com]         │
│  كلمة المرور:     [................   ]         │
│  التشفير:         [TLS              v]          │
│  اسم المُرسل:     [تطبيقي             ]         │
│  عنوان المُرسل:   [noreply@example.com]         │
└──────────────────────────────────────────────────┘

معالجة الأخطاء

جميع عمليات البريد الإلكتروني تُرجع Result<EmailResult, EmailError> مع أنواع أخطاء منظمة:

rust
match email.send(message).await {
    Ok(result) => println!("تم الإرسال: {}", result.message_id),
    Err(EmailError::InvalidAddress) => println!("عنوان بريد إلكتروني خاطئ"),
    Err(EmailError::ProviderError(msg)) => println!("خطأ المزود: {}", msg),
    Err(EmailError::TemplateNotFound(name)) => println!("القالب '{}' غير موجود", name),
    Err(EmailError::AttachmentTooLarge(size)) => println!("المرفق يتجاوز الحد: {} بايت", size),
    Err(e) => println!("خطأ غير متوقع: {}", e),
}

تحذير

معظم مزودي البريد الإلكتروني يفرضون حدود حجم المرفقات (عادة 10-25 ميجابايت). للملفات الكبيرة، ضع في الاعتبار الرفع إلى التخزين وتضمين رابط تنزيل في نص البريد الإلكتروني بدلاً من ذلك.

Released under the MIT License.