How to send a plain text email in Laravel 8 without using a blade?

Viewed 1989

How can I send a plain text email in Laravel 8 without using a blade?

All our email messages and templates are stored in a database, so using a blade is not applicable to us. I just want to pass in text to send.

Thanks.

3 Answers
Mail::raw('This is a simple text', function ($m) {
  $m->to('toemail@abc.com')->subject('Email Subject');
});

Don't forget to include

use Mail;

This is what I ended up doing, and I think it's a good solution.

I created a generic Mailable class called app\Mail\Message.php.

<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class Message extends Mailable {
    use Queueable, SerializesModels;

    private $theSubject;
    private $htmlBody;
    private $fromAddress;
    private $theAttachments;
    private $replyToEmail;

    public function __construct($subject, $htmlBody, $fromAddress, $replyTo=null, $attachments=null) {
        $this->theSubject = $subject;
        $this->htmlBody = $htmlBody;
        $this->fromAddress = $fromAddress;
        $this->theAttachments = $attachments;
        $this->replyToEmail = $replyTo;
    }

    public function getBody() {
        return $this->htmlBody;
    }


    public function build() {
        $this->subject($this->theSubject);
        $this->from($this->fromAddress);
        $this->html($this->htmlBody);

        if ($this->replyToEmail != null) {
            $this->replyTo($this->replyToEmail);
        }

        // more info here: https://laravel.com/docs/8.x/mail#attachments
        if ($this->theAttachments != null) {
            foreach($this->theAttachments as $attachment) {
                if (is_array($attachment)) {
                    $this->attach($attachment[0], [                     // $attachment[0] = temp file path
                        'as'    =>  (isset($attachment[1]) ? $attachment[1]:null),  // $attachment[1] = filename
                        'mime'  =>  (isset($attachment[2]) ? $attachment[2]:null),  // $attachment[2] = mime type
                    ]);
                } else {
                    $this->attach($attachment);     // $attachment = temp file path
                }
            }
        }
        
        return $this;
    }
}

To send an email, I do this:

$message = new Message($subject, $fullBody, $fromAddress, $replyTo, $attachments);
Mail::to($address)->send($message);

To test sending email, I do this:

Mail::fake();
Mail::assertNothingSent();

// do something that sends an email...

Mail::assertSent(Message::class, function($email) {
    $token = // get something that should be found in the body

    $email->build();
    $allGood = true;
    $allGood &= $email->subject === 'Password Recovery';
    $allGood &= str_contains($email->getBody(), $token);
    return $allGood;
});

I think you might be better of creating a Notification class that sends via mail. You can generate a notification with php artisan make:notification OrderShipped And by default its via method will send by mail, and will use Laravels default mail templates. In the toMail you can send whatever is needed. Then for your tests you can do:

public function testUserGetNotifiedIfOrderShipped())
{
    Notification::fake();

    // Hit some endpoints thats will send notification

    // Assert Admin gets notification
    Notification::assertSentTo(User::first(), OrderShipped::class);
}
Related