التعامل مع البريد الإلكتروني (Mail) في Laravel

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث

 مقدمة

يوفّر Laravel واجهة برمجية (API) سلسة و بسيطة للمكتبة الرائجة SwiftMailer مع برنامج تشغيل لكل من SMTP و Mailgun و SparkPost و Amazon SOS وتابع mail ، و sendmail. ممّا يسمح بالبداية في إرسال الرسائل الإكترونية بسرعة عبر خدمات محلية أو سحابية من اختيارك.

برامج التشغيل اللازمة

تكون برامج التشغيل المعتمدة على الوسائط مثل Mailgun و SparkPost في العادة أسرع وأسهل في الاستعمال من خوادم SMTP. استعمل أحد هذه برامج التشغيل إن أمكنك. تَستعمل كل المشغّلات التي تعتمد على الوسائط (API) المكتبة Guzzle التي يمكنك تثبيتها باستعمال منظم الحزم Composer.

composer require guzzlehttp/guzzle

برنامج التشغيل Mailgun

لاستخدام برنامج التشغيل Mailgun، أولًا ثبّت Guzzle ثمّ غير الخيار driver في ملف الضبط config/mail.php للقيمة mailgun. بعد ذلك، تثبت من أنّ ملف الضبط config/services.php يحتوي الخيار التالي:

'mailgun' => [

   'domain' => 'your-mailgun-domain',
   'secret' => 'your-mailgun-key',
],

برنامج التشغيل SparkPost

لاستخدام برنامج التشغيل SparkPost، أولا ثبّت Guzzle ثمّ غير الخيار driver في ملف الضبط config/mail.php للقيمة sparkpost. بعد ذلك، تثبت من أنّ ملف الضبط config/services.php يحتوي الخيار التالي:

'sparkpost' => [

   'secret' => 'your-sparkpost-key',
],

يمكن أيضًا ضبط نقطة نهاية الوسيط التي يجب استعمالها إن احتجت لذلك: '

sparkpost' => [

   'secret' => 'your-sparkpost-key',
   'options' => [
       'endpoint' => 'https://api.eu.sparkpost.com/api/v1/transmissions',
   ],
],

برنامج التشغيل SES

لاستخدام برنامج التشغيل Amazon SES يجب أولًا تثبيت Amazon AWS SDK الخاص بلغة PHP. يمكنك تثبيت المكتبة عبر إضافة السطر التالي للقسم require من الملف composer.json:

"aws/aws-sdk-php": "~3.0"

بعد ذلك غير الخيار driver في ملف الضبط config/mail.php إلى القيمة ses. ثمّ تثبت من أنّ ملف الضبط config/services.php يحتوي الخيار التالي:

'ses' => [

   'key' => 'your-ses-key',
   'secret' => 'your-ses-secret',
   'region' => 'ses-region', // e.g. us-east-1
],

إنشاء الأصناف القابلة للإرسال

في Laravel، كل نوع من الرسائل المرسلة من التطبيق تُمَثّل في صنف (class) قابل للإرسال "mailable". تُخزّن هذه الأصناف في المجلد app/Mail. لا تقلق إذا لم تجد المجلد في تطبيقك إذ سيصنع عندما تُنشِئ أول صنف قابل للإرسال باستعمال الأمر make:mail:

php artisan make:mail OrderShipped

كتابة الأصناف القابلة لإرسال

يُضبَط الصنف القابل للإرسال في التابع build. في هذا التابع، يمكنك نداء عدّة عوامل مثل from و subject و view و attach لضبط طريقة التقديم والإرسال.

ضبط المرسل

استعمال التابع from

لنبدأ أولا بضبط المرسِل، أو المكان الذي سيراه متلقي الرسالة كمصدر الإرسال. توجد طريقتان للقيام بهذا. أولًا، يمكنك استعمال التابع from داخل التابع build من الصنف القابل للإرسال:

/**

* بناء الرسالة
*
* @return $this
*/
public function build() {

   return $this->from('example@example.com')
               ->view('emails.orders.shipped');
}

استعمال عنوان عام from

في حالة كان للتطبيق عنوان واحد تُرسَل منه كل الرسائل، قد يصبح من غير المجدي نداء التابع from في كل صنف قابل للإرسال. عوض ذلك، يمكنك تحديد عنوان عام "from" في ملف الضبط config/mail.php. سيَستعمل هذا العنوان في حالة عدم ذكر عنوان خاص بالصنف القابل للإرسال

'from' => ['address' => 'example@example.com', 'name' => 'App Name'],

ضبط الواجهة

في التابع build من الصنف القابل للإرسال، يمكن نداء التابع view لتحديد أي القوالب يجب استعمالها حين إظهار محتوى الرسائل. حيث تستعمل الرسائل في الغالب قوالب Blade لإظهار المحتوى، لك كل قوة وسهولة استخدام المحرك blade لبناء الرسالة:

/**

* بناء الرسالة
*
* @return $this
*/
public function build() {

   return $this->view('emails.orders.shipped');
}

ملاحظة: قد ترغب بإنشاء المجلد resources/views/emails ليحتوي على قوالب الرسائل، لكنك حرّ في أن تضع القوالب في أي مكان تريد في المجلد resources/views.

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

يمكنك تعريف نص عادي للرسالة باستعمال التابع text. مثل view، يقبل text اسم القالب الذي سيُستعمل لإظهار محتوى الرسالة. أنت حر في الإختيار بين النسخة العادية ونسخة HTML للرسالة:

/**

* بناء الرسالة
*
* @return $this
*/
public function build() {

   return $this->view('emails.orders.shipped')
               ->text('emails.orders.shipped_plain');
}

إظهار البيانات

عبر الخصائص العمومية

تحتاج في العادة لتمرير بعض البيانات للواجهة لاستعمالها حين إظهار الرسالة. هناك طريقتان لتوفير البيانات للواجهة. أولًا، كل خاصية عامة (public property) معَرّفة في الصنف القابل للإرسال تكون تلقائيًا متاحةً في الواجهة. لذا، يمكنك مثلا تمرير بيانات للتابع الباني في الصنف ثم إعطاء هذه البيانات للخاصيات العامة في الصنف:

<?php

namespace App\Mail;

use App\Order; use Illuminate\Bus\Queueable; use Illuminate\Mail\Mailable; use Illuminate\Queue\SerializesModels;

class OrderShipped extends Mailable

{

   use Queueable, SerializesModels;
   /**
    * خاصية الترتيب 
    *
    * @var Order
    */
   public $order;
   /**
    * صناعة نسخة من الرسالة
    *
    * @return void
    */
   public function __construct(Order $order)
   {
       $this->order = $order;
   }
   /**
    *بناء الرسالة
    *
    * @return $this
    */
   public function build()
   {
       return $this->view('emails.orders.shipped');
   }
}

بعد ضبط البيانات، ستكون متاحة للاستعمال في الواجهة ويمكنك الوصول إليها كبقية البيانات في قوالب blade:

<div>
    Price: {{ $order->price }}
</div>

عبر التابع with

يمكنك تمرير البيانات يدويًا للواجهة باستعمال التابع with إذا أردت تخصيص شكل البيانات قبل إرسالها للقالب. في العادة، ستحتاج لتمرير البيانات للتابع الباني للصنف القابل للإرسال، لكن عليك تغيير صفة البيانات إلى protected أو private حتى لا تكون متاحة تلقائيًا للقالب. ثمّ عند نداء التابع with، مرّر مصفوفة البيانات المتاحة للقالب:

<?php namespace App\Mail; use App\Order; use Illuminate\Bus\Queueable; use Illuminate\Mail\Mailable; use Illuminate\Queue\SerializesModels; class OrderShipped extends Mailable {

   use Queueable, SerializesModels;
   /**
    * خاصية الترتيب.
    *
    * @var Order
    */
   protected $order;
   /**
    * صناعة الرسالة.
    *
    * @return void
    */
   public function __construct(Order $order)
   {
       $this->order = $order;
   }
   /**
    *
    * @return $this
    */
   public function build()
   {
       return $this->view('emails.orders.shipped')
                   ->with([
                       'orderName' => $this->order->name,
                       'orderPrice' => $this->order->price,
                   ]);
   }
}

بعد ضبط البيانات، ستكون متاحةً للاستعمال في الواجهة ويمكنك ولوجها كبقية البيانات في قوالب blade

<div>
    Price: {{ $order->price }}
</div>

المرفقات

لإضافة مرفقات للرسالة، يُستعمل التابع attach في التابع build من الصنف. يقبل التابع مسارًا كاملًا للملف كمعامل أول:

/** 
* بناء الرسالة 
* 
* @return $this
*/ 
public function build() 
{ return $this->view('emails.orders.shipped') ->attach('/path/to/file'); }

عند إرفاق ملف مع الرسالة، يمكنك تحديد اسم أو نوع MIME بتمرير مصفوفة كمعامل ثاني للتابع attach:

/**
 * بناء الرسالة.
 * 
 * @return $this
 */
 public function build()
 { return $this->view('emails.orders.shipped') ->attach('/path/to/file', [ 'as' => 'name.pdf', 'mime' => 'application/pdf', ]); }

إرفاق معلومات خام

يمكن استعمال التابع attachData لإرفاق معلومات خام في شكل سلسلة من البيانات الخام. مثلًا، يمكن استعمال هذا التابع لإحداث ملف PDF في الذاكرة و إرفاقها مباشرة بالرسالة دون تسجيلها في القرص الصلب. يقبل التابع attachData بايت (Bytes) من البيانات الخام كمعامل أول. اسم الملف كمعامل ثاني و مصفوفة خيارات كمعامل ثالث:

/** 
* بناء الرسالة. 
* 
* @return $this 
*/ 
public function build()
 { return $this->view('emails.orders.shipped')
 ->attachData($this->pdf, 'name.pdf', [ 'mime' => 'application/pdf', ]); }

المرفقات المُضمّنة

يكون تضمين صور في الرسائل في العادة عملية مرهقة وثقيلة، لكن Laravel يوفّر طريقة سهلة لإرفاق الصور بالرسائل واسترجاع رقم CID الملائم. لتضمين صورة، استعمل التابع embed على المتغيّر message$ في قالب الرسالة. يضيف Laravel تلقائيًا المتغيّر message$ إلى القالب، لذا لا تحتاج لتمريره يدويًا:

<body>

   هنا صورة : 
   <img src="{{ $message->embed($pathToFile) }}">
</body>

تنبيه: المتغير message$ غير موجود في الرسائل المكتوبة بصيغة Markdown.

تضمين مرفقات بيانات خام

إذا كان لديك معلومات بيانات خام تريد تضمينها في قالب الرسالة، يمكنك ذلك باستعمال التابع embedData على المتغيّر message$:

<body>

   هنا صورة من بيانات خام:
   <img src="{{ $message->embedData($data, $name) }}">
</body>

تخصيص رسائل SwiftMailer

يسمح التابع withSwiftMessage من الصنف الأصلي Mailable بتسجيل رد نداء يستدعى مع رسالة SwiftMAiler الخام قبل إرسال الرسالة. مما يعطيك إمكانية تخصيص و تكييف الرسالة قبل إرسالها:

 /**
    *  
    * @return $this
    */
   public function build()
   {
       $this->view('emails.orders.shipped');
       $this->withSwiftMessage(function ($message) {
           $message->getHeaders()
                   ->addTextHeader('Custom-Header', 'HeaderValue');
       });
   }

العناصر القابلة للإرسال Markdown

تسمح لك رسائل Markdown باستغلال قوالب و مكوّنات مصنوعة سابقًا في الرسالة. حيث أنّ الرسائل مكتوبة بلغة Markdown، يتمكن Laravel من إظهار قوالب جميلة و متجاوبة للرسالة و صناعة نسخةِ نص عادي في نفس الوقت.

إنشاء أصناف Markdown

لإنشاء أصناف قابلة للبعث Markdown، يمكن استعمال الخيار markdown-- مع الأمر make:mail:

php artisan make:mail OrderShipped --markdown=emails.orders.shipped

ثم عند ضبط الصنف في التابع build، استعمل markdown بدل view. يقبل التابع markdown اسم قالب Markdown ومصفوفة اختيارية من البيانات لإتاحتها للقالب:

/**

*
* @return $this
*/
public function build() {

   return $this->from('example@example.com')
               ->markdown('emails.orders.shipped');
}

كتابة رسائل Markdown

تستعمل أصناف Markdown خليطًا من مكوّنات Blade ونص Markdown مما يسمح ببناء الرسالة بسهولة باستعمال المكوّنات الجاهزة:

@component('mail::message')
# Order Shipped

Your order has been shipped!

@component('mail::button', ['url' => $url])
View Order
@endcomponent

Thanks,<br>
{{ config('app.name') }}
@endcomponent

ملاحظة: لا تكثر من استعمال الإزاحات فمحلّل اللغة في Markdown سيظهر النص ذا المساحات المُزاحة الكثيرة كنص شيفرة.

المكوّن button

يُظهر المكوّن button زرَّ ربط في وسط الصفحة. يقبل المكوّن معاملَين: مسار url ولونًا اختياريًا color. الألوان المدعومة هي blue و green و red. يمكنك إضافة أي عدد من الأزرار تريد

@component('mail::button', ['url' => $url, 'color' => 'green']) View Order @endcomponent

المكوّن panel

يُظهر المكوّن Panel النص المُمرّر كمجموعة بخلفية مختلفة قليلًا عن بقية الرسالة مما يسمح بجذب الانتباه لهذا النص:

@component('mail::panel') This is the panel content.

@endcomponent

المكوّن table

يسمح المكوّن table بتحويل جدول Markdown لجدول HTML. يقبل المكوّن جدول Markdown كمحتوى ويدعم المحاذاة باستخدام تنسيق Markdown:

@component('mail::table')
| Laravel       | Table              | Example  |
| ---------------|:-----------------:| ------------:|
| Col 2 is       | Centered       | $10          |
| Col 3 is       | Right-Aligned| $20          |
@endcomponent

تخصيص المكوّنات

يمكنك تحميل كل المكونات من Markdown في التطبيق لتخصيصها. لتحويل المكونات، استعمل الأمر vendor:publish لنشر الأصول laravel-mail:

php artisan vendor:publish --tag=laravel-mail

سيُحمّل هذا الأمر مكونات Markdown في المجلد resources/views/vendor/mail. سيحتوي المجلد mail على المجلد html ومجلد markdown، كل منهما يحتوي على النسخة الملائمة من المكوّنات. تُستخدم المكونات في المجلد html لبناء نسخة html من الرسالة في حين تُستخدم المكونات من المجلد Markdown لبناء نسخة نص عادي. لك حرية تخصيص هذه المكونات كما تريد.

تخصيص ال CSS

بعد تحميل المكونات، يحتوي المجلد resources/views/vendor/mail/html/themes على ملف css المبدئي default.css. يمكنك تخصيص تخطيط CSS في هذا الملف وسيُضمّن تلقائيًا في عرض HTML لرسائل Markdown.

ملاحظة : إذا أردت بناء نمط جديد لمكون Markdown، اكتب ملف CSS جديد في المجلد html/themes وغيّر الخيار theme في ملف الضبط mail.

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

لإرسال رسالة، استعمل التابع to من الواجهة الثابتة Mail. يقبل التابع to عنوانًا إلكترونيًا، أو نسخة من كائن مستخدم، أو مجموعة مستخدمين. إذا مرّرت كائنًا أو مجموعة كائنات، ستُستخدم الخاصيات mail و name من الكائن عند ضبط متلقي الرسالة. بعد ضبط المتلقي، يمكنك تمرير مثيل من الصنف للتابع send:

<?php

namespace App\Http\Controllers;

use App\Order;
use App\Mail\OrderShipped;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use App\Http\Controllers\Controller;

class OrderController extends Controller
{
    /**
     * Ship the given order.
     *
     * @param  Request  $request
     * @param  int  $orderId
     * @return Response
     */
    public function ship(Request $request, $orderId)
    {
        $order = Order::findOrFail($orderId);

       // Ship order...

        Mail::to($request->user())->send(new OrderShipped($order));
    }
}

طبعًا لست محدودًا باستعمال to لضبط المتلقي، يمكنك أيضا ضبط cc و bcc في نداء واحد:

Mail::to($request->user())

   ->cc($moreUsers)
   ->bcc($evenMoreUsers)
   ->send(new OrderShipped($order));

عرض الأصناف القابلة للإرسال

قد تحتاج في بعض الأحيان لإظهار محتوى صنف قابل للإرسال دون إرساله، للقيام بهذا يمكن استعمال التابع render. يعيد هذا التابع النتيجة الحاصلة من الصنف على شكل سلسلة نصية:

$invoice = App\Invoice::find(1);

return (new App\Mail\InvoicePaid($invoice))->render();

معاينة الأصناف في المتصفح

عند تصميم قالب صنف قابل للإرسال، من المفيد أن تتمكن من معاينة نتيجة الصنف الممرّرة في المتصفح كأي قالب Blade. لهذا، يسمح Laravel بإعادة أي صنف قابل للإرسال من وحدات التحكم أو مسارات closure. عندما يعاد الصنف، سيُظهَر في المتصفح لمعاينة التصميم بسرعة دون الحاجة لإرسال الرسالة:

Route::get('/mailable', function () {

   $invoice = App\Invoice::find(1);
   return new App\Mail\InvoicePaid($invoice);
});

إضافة الرسائل لطابور الإنتظار

إضافة الرسالة

حيث يطوّل إرسال البريد الاكتروني وقت إجابة التطبيق، يختار العديد من المطوّرين إضافة الرسائل لطابور انتظار لإرسالها في خلفية التطبيق. يُتيح Laravel إمكانية القيام هذا بسهولة باستخدام API Unified queue. لإضافة الرسائل لطابور الانتظار، استعمل التابع queue من الواجهة الساكنة Mail بعد تحديد متلقي الرسالة:

Mail::to($request->user())

   ->cc($moreUsers)
   ->bcc($evenMoreUsers)
   ->queue(new OrderShipped($order));

سيتكفّل التابع بدفع مهمّة لطابور الإنتظار تقوم بإرسال الرسالة في خلفية التطبيق. ستحتاج طبعًا لضبط طوابير الإنتظار قبل استعمال هذه الخاصية.

تأخير إضافة الرسالة

إذا أردت تأخير إرسال رسالة ما في طابور الانتظار، استعمل التابع later. يقبل هذا التابع نسخة الكائن DateTime يوضّح وقت الإرسال

$when = now()->addMinutes(10);

Mail::to($request->user())

   ->cc($moreUsers)
   ->bcc($evenMoreUsers)
   ->later($when, new OrderShipped($order));

الإضافة لطابور انتظار معيّنة

حيث أنّ كل الأصناف القابلة للإرسال تُصنع ياستعمال الأمر mail:make لخاصيات Illuminate\Bus\Queueable، يمكن استعمال التابعين onQueue و onConnection على أي نسخة لصنف قابل للإرسال. مما يسمح بتحديد الصلة وقائمة الانتظار لكل رسالة:

$message = (new OrderShipped($order))

               ->onConnection('sqs')
               ->onQueue('emails');
Mail::to($request->user())

   ->cc($moreUsers)
   ->bcc($evenMoreUsers)
   ->queue($message);

الإضافة المبدئية

إذا كان لديك أصناف قابلة للإرسال تريد أن تضيفها دائمًا لقائمة الانتظار، يمكنك تنفيذ العقد ShouldQueue في الصنف. في هذه الحال، حتى إن ناديت التابع send للإرسال فإنّ الصنف سيضاف للقائمة باعتباره حاملًا للعقد:

use Illuminate\Contracts\Queue\ShouldQueue;

class OrderShipped extends Mailable implements ShouldQueue {

  //
}

الرسائل الإلكترونية والتطوير المحلي

عند تطوير تطبيق، قد لا تريد إرسال بريد لعناوين حقيقية. يوفّر Laravel طرائق عديدة لتعطيل عملية الإرسال في مرحلة التطوير.

المشغل Log

بدل إرسال الرسائل، يكتب المشغل Log محتوى الرسائل في ملف log لمعاينتها. لمزيد من المعلومات حول بيئة التطوير، تفقّد توثيق الضبط.

To العام

حل آخر يوفره Laravel هو ضبط متلقي عام تُرسل إليه كل الرسائل من التطبيق. بهذه الطريقة، ستُرسل كل الرسائل من التطبيق إلى العنوان محدّد بدل العنوان المذكور كمتلقي للرسالة. يمكن القيام بهذا باستعمال الخيار to في ملف الضبط config/mail.php:

'to' => [

   'address' => 'example@example.com',
   'name' => 'Example'
],

Mailtrap

في الأخير يمكن استخدام خدمة مثل Mailtrap و المشغل smtp لإرسال الرسائل لعنوان وهمي حيث يمكنك رؤيتها من تطبيق رسائل حقيقي. تسمح هذه الطريقة بمعاينة الرسالة النهائية في قارئ رسائل Mailtrap.

الأحداث

يطلق Laravel حدثين في عملية الإرسال. يُطلق الحدث MessageSending قبل إرسال الرسالة في حين يُطلق MessageSent بعد البعث. هذه الأحداث تُطلق حين إرسال الرسائل وليس حين إضافتها لقائمة الإنتظار. يمكنك تسجيل مستمعات لهذه الأحداث في الملف ُEventServiceProvider:

/**

* المستمعات على الأحداث في التطبيق
*
* @var array
*/
protected $listen = [

   'Illuminate\Mail\Events\MessageSending' => [
       'App\Listeners\LogSendingMessage',
   ],
   'Illuminate\Mail\Events\MessageSent' => [
       'App\Listeners\LogSentMessage',
   ],
];

مصادر