I solved my issue using the markdown method, since Markdown email templates create both a plain text and full HTML version.
Plain text emails for notifications?
Is it possible to explicitly specify a plain text email template, and send both a formatted email and a plain text email, through the Notifications system? I have attempted to use the text() method on the MailMessage class, but apparently that method does not exist.
You can use view() instead of markdown().
public function toMail($notifiable)
{
return (new MailMessage)
->subject('subject')
->view('emails.viewname', ['param' => $this->param]);
}
@yusukeokui that doesn't create a text-only part :P
@cconover, markdown() doesn't solve the matter if you have more complicated email templates (lucky you!)
I requested that text() should be included on MailMessage as well, but in the meantime, you can return a Mailable instead.
To make matters "simpler", I created a BareMail class to help on that, so you don't have to create separate classes just to configure a couple of commands (all Mailable methods are public anyway...):
class Welcome extends Notification {
//[...]
public function toMail(User $user) {
return (new BareMail)
->to($user->email) //don't forget this!
->subject('Welcome to the app')
->view('emails.welcome', ['user' => $user])
->text('emails.welcome.text');
}
}
class BareMail extends Mailable {
use Queueable, SerializesModels;
public function build() {}
}
@igorsantos07 great solution, thank you for suggesting it.
You can create Mailable class and use it in notifications. And mailables supports plain text. Read more in official Laravel docs.
- https://laravel.com/docs/9.x/notifications#using-mailables
- https://laravel.com/docs/9.x/mail#plain-text-emails
use App\Mail\InvoicePaid as InvoicePaidMailable;
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return Mailable
*/
public function toMail($notifiable)
{
return (new InvoicePaidMailable($this->invoice))
->to($notifiable->email);
}
Thanks @lukas.pierce for the hint. Using a Mailable is a decent workaround, but remember to use text() instead of view() to build a plain-text only email notification (if you don't want to provide a Content definition by overriding the Mailable):
class Welcome extends Notification {
//[...]
public function toMail(User $notifiable)
{
return (new Mailable)
->to($notifiable->email) // this is needed!
->subject('Welcome to the app')
->text('emails.welcome', ['user' => $user]);
}
}
Like this, there is no need to extend/override Mailable.
But after all, I prefer using MailMessage instead of a Mailable in all notifications, so that the to is automatically applied as recipient, from the Notifiable's standard routeNotificationForMail() method (or from the default email field if you use a model as Notifiable and don't override this method) on MailChannel::getRecipients().
There is no MailMessage::text() method as mentioned by @igorsantos07 [Proposal] Add text/plain part to MailMessage.
Here's the crucial part which does not seem to be documented anywhere in Laravel docs:
So, if you want to use MailMessage for plain-text only notifications, just use an array as $view param in view() method, where you only fill text (your view template key) or raw (your pre-rendered plaintext body) like so:
class Welcome extends Notification {
//[...]
public function toMail(User $notifiable)
{
return (new MailMessage)
->subject('Welcome to the app')
->view(['text' => 'emails.welcome'], ['user' => $user])
// ->view(['raw' => 'Some email body...']) // alternatively, if you want to provide pre-rendered text
->text('emails.welcome', ['user' => $user]);
}
}
This definitely seems to be the simplest we can go to send out plain-text only email notifications, without reinventing the wheel. Hope this helps some others save some time, as I wasted way too much on it and that was actually a big pain point already 3yrs ago when I started with Laravel. Should really make it into the docs, this hidden feature! I might PR text() and raw() helper methods on MailMessage.
Cheers, Philip
I was facing something similar, here is my solution. Might be useful for some devs too.
I wanted to do similar thing. Every time notification is sent to "normal" email, I want to use all benefits of Markdown templates. But when it goes to Basecamp (adding as ticket) it must be plain text format. However, I don't want to define same email template twice, so I used this little hack with callback.
If email goes to Basecamp, I just remove HTML part, just before it is sent out.
class TripCreatedNotification extends Notification
{
public function toMail(): MailMessage
{
return (new MailMessage())
->subject('subject')
->markdown('mail.trip.created', ['trip' => $this->trip])
->withSymfonyMessage(static function (Email $message): void {
$goesToBasecamp = \collect($message->getTo())->first(
static fn ($to) => Str::match('#\@([0-9]+\.)basecamp\.com$#i', $to->getAddress()),
);
if ($goesToBasecamp) {
$message->html(null);
}
});
}
}
Please or to participate in this conversation.