Laravel邮件:传递字符串而非视图

88

我希望使用 Laravel 发送确认电子邮件。 然而,Laravel 的 Mail::send() 函数只接受系统上文件的路径作为参数。 问题在于,我的邮件模板是存储在数据库中而不是系统文件中。

我该如何向邮件传递纯文本内容?

例如:

$content = "Hi,welcome user!";

Mail::send($content,$data,function(){});
13个回答

183

2022年7月20日更新:对于更高版本的Laravel,下面Mail::send()示例中的setBody()方法已被替换为text()html()方法。

更新:在Laravel 5中,您可以使用raw代替:

Mail::raw('Hi, welcome user!', function ($message) {
  $message->to(..)
    ->subject(..);
});

这就是操作步骤:

Mail::send([], [], function ($message) {
  $message->to(..)
    ->subject(..)
    // here comes what you want
    ->setBody('Hi, welcome user!'); // assuming text/plain
    // or:
    ->setBody('<h1>Hi, welcome user!</h1>', 'text/html'); // for HTML rich messages
});

对于 html 邮件(需要额外的参数),请参见 @sajjad-ashraf 的答案。合并可能是个好主意? - Bryan
1
true,添加如@Sajjad的答案中所述。 - Jarek Tkaczyk
1
如何在 Laravel 5 中设置 text/html? - Toskan
3
如果你想使用 Mail::queue 来发送邮件,则很遗憾这个方法行不通,会抛出一个无效参数异常:“仅可排队可发送的邮件。” - Hlorofos
值得一提的是使用Mailable更好。但对于像我这样正在寻找Mail::raw回调范围解决方案的人,您可以使用匿名函数,如此答案所示。 - Marcos Rocha
显示剩余2条评论

60

对于HTML电子邮件

Mail::send(array(), array(), function ($message) use ($html) {
  $message->to(..)
    ->subject(..)
    ->from(..)
    ->setBody($html, 'text/html');
});

据推测,您可以设置多个具有不同内容类型的正文,因此可以创建包含text/htmltext/plain部分的多部分电子邮件。 - Jason
3
当设置了HTML部分时,@Jason该函数(https://github.com/laravel/framework/blob/master/src/Illuminate/Mail/Mailer.php#L320)使用`addPart()`来添加纯文本部分而不是`setBody()`。 - Philip
1
你能帮我解决这个问题吗?我的代码如下:$html = "Hello {{username}}", 我该如何动态地传递用户名? - Vipertecpro

18

这与问题不直接相关,但对于那些想要设置纯文本版本电子邮件并保留自定义HTML版本的人来说,您可以使用以下示例:

Mail::raw([], function($message) {
    $message->from('contact@company.com', 'Company name');
    $message->to('johndoe@gmail.com');
    $message->subject('5% off all our website');
    $message->setBody( '<html><h1>5% off its awesome</h1><p>Go get it now !</p></html>', 'text/html' );
    $message->addPart("5% off its awesome\n\nGo get it now!", 'text/plain');
});

如果你问“为什么不把第一个参数设置为纯文本?”,我做了一个测试,它只会采用HTML部分,而忽略原始部分。

如果你需要使用额外的变量,这个匿名函数将需要你使用use()语句,如下所示:

Mail::raw([], function($message) use($html, $plain, $to, $subject, $formEmail, $formName){
    $message->from($fromEmail, $fromName);
    $message->to($to);
    $message->subject($subject);
    $message->setBody($html, 'text/html' ); // dont miss the '<html></html>' or your spam score will increase !
    $message->addPart($plain, 'text/plain');
});

希望这能帮到你们。


13

Mailer类将一个字符串传递给addContent方法,该方法通过其他各种方法调用views->make()。因此,直接传递一串内容将不起作用,因为它会尝试按名称加载视图。

您需要做的是创建一个视图,只需回显$content即可。

// mail-template.php
<?php echo $content; ?>

然后在运行时将您的字符串插入到该视图中。

$content = "Hi,welcome user!";

$data = [
    'content' => $content
];

Mail::send('mail-template', $data, function() { });

9
不太优雅,我更喜欢Jarek Tkaczyk的方式 :) - Ifnot
2
这个答案非常误导人,不知道为什么提问者接受了这个答案。Jarek Tkaczyk和Sajjad Ashraf已经正确回答了它。 - Rohit Kapali

6

尝试

public function build()
{
    $message = 'Hi,welcome user!'
    return $this->html($message)->subject($message);
}

6

我遇到了一个类似的问题,即我的电子邮件的HTML和/或纯文本不是通过视图构建的,我不想为它们创建一个虚拟视图(如@Matthew Odedoyin所建议的那样)。

正如其他人所评论的那样,您可以使用$this->html()来设置消息的HTML内容,但是如果您希望电子邮件具有HTML和纯文本内容,该怎么办?

不幸的是,$this->text()只接受视图,但我通过使用以下方法解决了这个问题:

$this->text(new HtmlString('Here is the plain text content'));

这将呈现HTMLString内容而不是视图。


+1。这是唯一对我有用的答案,因为我提前构建了可邮寄对象,所以无法使用send()方法。令人失望的是,为了制作多部分电子邮件,需要这种解决方法,而HTML已经有一种将其作为字符串添加的方法。 - theberzi
这正是我所需要的。Mailtrap有一个“文本”选项卡,显示电子邮件的纯文本版本,适用于任何使用Mailtrap进行测试的人。 - Sammy AbuKmeil

3

如您所知

只有可邮寄的才可以排队。

也就是说,如果您使用了 ShouldQueue 接口

1)首先,您应该始终执行

php artisan queue:restart

2)其次,在您的可邮寄对象中,您可以使用html方法(已在Laravel 5.8中测试)。

public function build(): self
{
    return $this
            ->html('
                <html>
                    <body>
                        ForwardEmail
                    </body>
                </html>
            ')
            ->subject(config('app.name') . ' ' . 'email forwarded')
            ->attachData($this->content, 'email.eml', [
                'mime' => 'application/eml',
    ]);
}

2
如果您正在使用可发送邮件的功能,您可以在build方法中执行以下操作:
public function build()
{
 
    return $this->view('email')
        ->with(['html'=>'This is the message']);
}

你只需要在资源文件夹中创建名为email.blade.php的刀片视图。

然后在刀片视图中,你可以使用Laravel Blade语法引用你的字符串。

 <html>
    <body>
      {{$html}}
    </body>
  </html>

或者

 <html>
    <body>
      {!!$html!!}
    </body>
 </html>

如果您的原始文本包含HTML标记,我希望这对那些在数据库中存储模板并想利用Laravel中的Mailables类的人有所帮助。

OP说他们不想使用视图。 - dazed-and-confused

1
你可以在 Laravel Mailables 中重写 Mailable->send() 方法来发送原始的 HTML、文本等内容。在那里,使用先前响应中的方法即可。
send([], [], function($message){ $message->setBody() } )

无需在您的构建函数中调用$this->view()。

1

注意:以下答案适用于寻求灵活方法的人,即(使用或不使用Laravel模板)

使用模板

 $payload['message'] = View::make('emails.test-mail',$data)->render();

无模板

$payload['message'] = "lorem ipsum";


Mail::raw([], function ($mail) use ($payload) {
    $mail->from($payload['from_email'])
        ->to($payload['to'])
        ->setBody($payload['message'], 'text/html')
        ->cc($payload['cc'])
        ->bcc($payload['bcc'])
        ->subject($payload['subject']);
    foreach ($payload['attachments'] as $file){
        $mail->attach($file);
    }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接