对 Laravel 5 发送邮件队列感到困惑 (Laravel 5.4)
Confused about Laravel 5 Queue for Sending Mail (Laravel 5.4)
我从Laravel4.1
升级到5.4
。队列迁移困难
首先,我从 routes:
中注释掉了 iron
route
Route::post('queue/receive', function()
{
return Queue::marshal();
});
然后,我配置了数据库驱动并迁移了jobs
table:
php artisan queue:table
php artisan migrate
我将 Mail::queue
代码更改为 Mailables,如下所示:
Mail::to('person@gmail.com')->send(new ForgotPassword($user->first_name));
同步发送邮件成功(无队列)。然后,我切换到队列:
Mail::to('person@gmail.com')->queue(new ForgotPassword($user->first_name));
最后,我 运行 来自控制台的命令:
php artisan queue:listen
当执行 Mail::to
行时,会在 Jobs
table 中插入一行,但不会发送邮件。我该如何解决这个问题?
注:ForgotPassword
是一个Mailable
class(应该是Job
class?)。
您可能需要编辑计算机上项目文件夹中现有的 .env 文件。
找到.env文件,通过sublime text打开并编辑。
使用您要发送邮件的电子邮件 ID 和密码进行编辑。
您可以使用 laravel 队列发送邮件,请参阅示例,
定义作业
public function handle()
{
$mail_meta_data = $this->send_data;
$require_data = $this->require_data;
Mail::queue($mail_meta_data['view_name'], ['data'=>$require_data], function($message) use ($mail_meta_data, $require_data) {
//$message->from($mail_meta_data['to'], $mail_meta_data['name']);
$message->to($mail_meta_data['to'])->subject($mail_meta_data['subject']);
});
}
调用作业
dispatch(new SendEmailNotification($mail_meta_data, $require_data));
.env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=smtp_username
MAIL_PASSWORD=smptp_password
MAIL_ENCRYPTION=tls
APP_EMAIL=email sent from
APP_NAME=Name of Email sender
备注
- 确保您已在 .env 文件或 config/mail.php
中设置上述邮件配置
- 也是phpartisanqueue:listen是运行
就您的 ForgotPassword
对象而言,同步 send()
和异步 queue()
之间的主要区别在于,当您将对象排队等待发送时,它必须被序列化以发送到队列,并在队列工作者处理它时反序列化。
由于 send()
工作正常,但 queue()
发生错误,我们可以看到排队的作业被触发并试图被处理,很可能是错误serialization/unserialization.
您的 ForgotPassword
class 可能正在使用 SerializesModels
特征,因为这就是 artisan 命令生成新的可邮寄对象的方式。此特征定义了 __sleep()
and __wakeup()
方法,这些方法修改了序列化和反序列化的工作方式。
当__sleep
方法实现时,PHP只会序列化__sleep
方法返回的变量。在这种情况下,SerializesModels
trait 提供的实现使用反射来遍历 class 上定义的属性,以提供一种特殊的方式来序列化 Eloquent 模型和集合。
正因为如此,这意味着 ForgotPassword
class 上任何未明确定义为 class 上的 属性 的变量都不会被序列化,当排队的作业被处理并且 class 被反序列化时,它将不可用。这是您遇到问题的最可能原因。当您的工作正在尝试时,您的未序列化的可邮寄实例没有它需要的数据,并且正在失败。
有两种方法可以解决这个问题。首先,如果您的 ForgotPassword
实际上不需要序列化任何模型,您可以删除 SerializedModels
特性。这将从 class 中删除 __sleep()
定义,然后在 class 上分配的所有变量,而不仅仅是那些实际定义的变量,将被序列化,并且在 class 未序列化。
第二个选项更合适也更明确,是在 ForgotPassword
class.
上实际定义您需要的属性
如果您在 class 上定义属性,则可以在 class 上保留 SerializesModels
特征。但是,如果您实际上没有序列化模型,我会继续删除它。如果不需要,则无需额外的序列化开销。
我从Laravel4.1
升级到5.4
。队列迁移困难
首先,我从 routes:
中注释掉了iron
route
Route::post('queue/receive', function()
{
return Queue::marshal();
});
然后,我配置了数据库驱动并迁移了jobs
table:
php artisan queue:table
php artisan migrate
我将 Mail::queue
代码更改为 Mailables,如下所示:
Mail::to('person@gmail.com')->send(new ForgotPassword($user->first_name));
同步发送邮件成功(无队列)。然后,我切换到队列:
Mail::to('person@gmail.com')->queue(new ForgotPassword($user->first_name));
最后,我 运行 来自控制台的命令:
php artisan queue:listen
当执行 Mail::to
行时,会在 Jobs
table 中插入一行,但不会发送邮件。我该如何解决这个问题?
注:ForgotPassword
是一个Mailable
class(应该是Job
class?)。
您可能需要编辑计算机上项目文件夹中现有的 .env 文件。 找到.env文件,通过sublime text打开并编辑。
使用您要发送邮件的电子邮件 ID 和密码进行编辑。
您可以使用 laravel 队列发送邮件,请参阅示例,
定义作业
public function handle()
{
$mail_meta_data = $this->send_data;
$require_data = $this->require_data;
Mail::queue($mail_meta_data['view_name'], ['data'=>$require_data], function($message) use ($mail_meta_data, $require_data) {
//$message->from($mail_meta_data['to'], $mail_meta_data['name']);
$message->to($mail_meta_data['to'])->subject($mail_meta_data['subject']);
});
}
调用作业
dispatch(new SendEmailNotification($mail_meta_data, $require_data));
.env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=smtp_username
MAIL_PASSWORD=smptp_password
MAIL_ENCRYPTION=tls
APP_EMAIL=email sent from
APP_NAME=Name of Email sender
备注
- 确保您已在 .env 文件或 config/mail.php 中设置上述邮件配置
- 也是phpartisanqueue:listen是运行
就您的 ForgotPassword
对象而言,同步 send()
和异步 queue()
之间的主要区别在于,当您将对象排队等待发送时,它必须被序列化以发送到队列,并在队列工作者处理它时反序列化。
由于 send()
工作正常,但 queue()
发生错误,我们可以看到排队的作业被触发并试图被处理,很可能是错误serialization/unserialization.
您的 ForgotPassword
class 可能正在使用 SerializesModels
特征,因为这就是 artisan 命令生成新的可邮寄对象的方式。此特征定义了 __sleep()
and __wakeup()
方法,这些方法修改了序列化和反序列化的工作方式。
当__sleep
方法实现时,PHP只会序列化__sleep
方法返回的变量。在这种情况下,SerializesModels
trait 提供的实现使用反射来遍历 class 上定义的属性,以提供一种特殊的方式来序列化 Eloquent 模型和集合。
正因为如此,这意味着 ForgotPassword
class 上任何未明确定义为 class 上的 属性 的变量都不会被序列化,当排队的作业被处理并且 class 被反序列化时,它将不可用。这是您遇到问题的最可能原因。当您的工作正在尝试时,您的未序列化的可邮寄实例没有它需要的数据,并且正在失败。
有两种方法可以解决这个问题。首先,如果您的 ForgotPassword
实际上不需要序列化任何模型,您可以删除 SerializedModels
特性。这将从 class 中删除 __sleep()
定义,然后在 class 上分配的所有变量,而不仅仅是那些实际定义的变量,将被序列化,并且在 class 未序列化。
第二个选项更合适也更明确,是在 ForgotPassword
class.
如果您在 class 上定义属性,则可以在 class 上保留 SerializesModels
特征。但是,如果您实际上没有序列化模型,我会继续删除它。如果不需要,则无需额外的序列化开销。