مزودو البريد الإلكتروني
يدعم FORGE إرسال رسائل البريد الإلكتروني التعاملية عبر drivers مزودين متعددة. يتعامل نظام البريد الإلكتروني مع التحقق من الحساب وإعادة تعيين كلمة المرور والإشعارات وأي بريد إلكتروني مخصص يحتاج تطبيقك لإرساله.
سمة EmailProvider
جميع drivers البريد الإلكتروني تُنفّذ سمة EmailProvider:
#[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 تحكماً كاملاً في تكوين البريد الإلكتروني:
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 تؤكد التسليم:
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_host | string | -- | اسم مضيف خادم SMTP |
email_port | number | 587 | منفذ خادم SMTP |
email_username | string | -- | اسم مستخدم مصادقة SMTP |
email_password | encrypted | -- | كلمة مرور مصادقة SMTP |
email_encryption | string | "tls" | طريقة التشفير: tls، ssl، أو none |
email_from_address | string | -- | عنوان بريد المُرسل الافتراضي |
email_from_name | string | -- | اسم عرض المُرسل الافتراضي |
نصيحة
SMTP هو الـ driver الافتراضي ويعمل مباشرة. للتطوير المحلي، استخدم Mailhog مع email_host: localhost، email_port: 1025، و email_encryption: none لالتقاط جميع رسائل البريد الصادرة بدون تسليمها فعلياً.
منافذ SMTP الشائعة
| المنفذ | البروتوكول | حالة الاستخدام |
|---|---|---|
25 | SMTP | ترحيل خادم إلى خادم (غالباً محظور من ISPs) |
465 | SMTPS | SSL/TLS ضمني |
587 | SMTP | إرسال مع STARTTLS (موصى به) |
1025 | SMTP | Mailhog / التطوير المحلي |
SendGrid
تسليم البريد الإلكتروني السحابي عبر SendGrid API. يوفر SendGrid إرسالاً عالي الحجم وتحليلات التسليم وإدارة القوالب من خلال لوحة التحكم.
التثبيت:
forge provider:add email:sendgridالإعدادات:
| الإعداد | النوع | الوصف |
|---|---|---|
sendgrid_api_key | encrypted | SendGrid API Key |
email_from_address | string | عنوان بريد المُرسل المُحقق |
email_from_name | string | اسم عرض المُرسل الافتراضي |
الميزات:
- رسائل البريد التعاملية -- إرسال عالي قابلية التسليم مُحسّن للرسائل المُولّدة من التطبيق
- إدارة القوالب -- إنشاء وإدارة قوالب البريد في لوحة تحكم SendGrid، ثم الإشارة إليها بالمعرّف
- تتبع التسليم -- حالة التسليم في الوقت الفعلي ومعدلات الفتح وتتبع النقرات
- Webhooks -- استقبال ردود الاتصال لأحداث التسليم (delivered، bounced، opened، clicked)
تحذير
يتطلب SendGrid التحقق من المُرسل. تأكد من التحقق من email_from_address في حساب SendGrid قبل الإرسال. سيتم رفض المُرسلين غير المُحققين.
Mailgun
تسليم البريد الإلكتروني عبر Mailgun API.
التثبيت:
forge provider:add email:mailgunالإعدادات:
| الإعداد | النوع | الوصف |
|---|---|---|
mailgun_api_key | encrypted | Mailgun API Key |
mailgun_domain | string | نطاق الإرسال في Mailgun |
mailgun_region | string | منطقة API: us أو eu |
email_from_address | string | عنوان المُرسل الافتراضي |
email_from_name | string | اسم عرض المُرسل الافتراضي |
Amazon SES
تسليم البريد الإلكتروني عبر Amazon Simple Email Service.
التثبيت:
forge provider:add email:sesالإعدادات:
| الإعداد | النوع | الوصف |
|---|---|---|
ses_access_key | encrypted | AWS Access Key ID |
ses_secret_key | encrypted | AWS Secret Access Key |
ses_region | string | منطقة AWS (مثل us-east-1) |
email_from_address | string | عنوان المُرسل المُحقق |
email_from_name | string | اسم عرض المُرسل الافتراضي |
تحذير
يبدأ Amazon SES في وضع sandbox، الذي يسمح فقط بالإرسال إلى عناوين بريد إلكتروني مُحققة. اطلب وصول الإنتاج من خلال وحدة تحكم AWS للإرسال بدون قيود.
الاستخدام
إنشاء المزود
يُنشئ المصنع الـ driver الصحيح بناءً على إعداداتك:
use crate::services::email::EmailFactory;
let email = EmailFactory::create(&settings).await?;إرسال بريد إلكتروني عادي
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);الإرسال مع مرفقات
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?;إرسال بريد إلكتروني بقالب
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?;نصيحة
رسائل البريد الإلكتروني المبنية على القوالب موصى بها لجميع الرسائل الموجهة للمستخدمين. تُبقي محتوى البريد الإلكتروني منفصلاً عن منطق التطبيق وتسمح لغير المطورين بتعديل نص البريد من خلال لوحة الإدارة أو لوحة تحكم المزود.
التحقق من عنوان بريد إلكتروني
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> مع أنواع أخطاء منظمة:
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 ميجابايت). للملفات الكبيرة، ضع في الاعتبار الرفع إلى التخزين وتضمين رابط تنزيل في نص البريد الإلكتروني بدلاً من ذلك.