Using e-mails in your package works very much the same as in a normal Laravel application. However, in your package, you need to make sure you are loading a views
directory from your package (or the end-user's exported version of it).
To start sending e-mails, we need to create 1) a new mailable and 2) an e-mail template.
The e-mail template can be in either markdown or blade template format, as you're used to. In this example, we'll focus on writing a Blade template, however if you're using a markdown template replace the $this->view('blogpackage::mails.welcome')
with a call to $this->markdown('blogpackage::mails.welcome')
. Notice that we're using the namespaced view name, allowing our package users to export the views and update their contents.
Creating a Mailable
First, add a new Mail
folder in the src/
directory, which will contain your mailables. Let's call it WelcomeMail.php
mailable. Since we've been working with a Post
model in the previous sections, let's accept that model in the constructor and assign it to a public $post
property on the mailable.
<?php
namespace JohnDoe\BlogPackage\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use JohnDoe\BlogPackage\Models\Post;
class WelcomeMail extends Mailable
{
use Queueable, SerializesModels;
public $post;
public function __construct(Post $post)
{
$this->post = $post;
}
public function build()
{
return $this->view('blogpackage::emails.welcome');
}
}
Registering the Views Directory
In the call to the mailable's view()
method we've specified the string emails.welcome
, which Laravel will translate to searching for a welcome.blade.php
file in the emails
directory in the package's registered views directory.
To specify a view directory, you need to add the $this->loadViews()
call to your package's service provider in the boot()
method. View files can be referenced by the specified namespace, in this example, 'blogpackage'. Note: if you're following along since the section about Routing, you've already done this.
<?php
public function boot()
{
// ... other things
$this->loadViewsFrom(__DIR__.'/../resources/views', 'blogpackage');
}
This will look for views in the resources/views
directory in the root of your package.
Creating a Blade Mail Template
Create the welcome.blade.php
file in the resources/views/emails
directory, where the $post
variable will be freely available to use in the template.
<p>
Dear reader,
Post title: {{ $post->title }}
-- Sent from the blogpackage
</p>
Testing Mailing
To test that e-mailing works and the mail contains all the right information, Laravel's Mail facade offers a built-in fake()
method which makes it easy to swap the real mailer for a mock in our tests.
To demonstrate how to test our e-mail, create a new WelcomeMailTest
in the tests/unit
directory. Next, in the test:
- Switch the Mail implementation for a mock using
Mail::fake()
. - Create a
Post
using our factory (see section Models and Migrations). - Assert that at this stage, no e-mails are sent using
assertNothingSent()
. - Send a new
WelcomeMail
mailable, passing in thePost
model. - Assert that the e-mail was sent and contains the correct
Post
model usingassertSent()
.
<?php
namespace JohnDoe\BlogPackage\Tests\Unit;
use Illuminate\Support\Facades\Mail;
use JohnDoe\BlogPackage\Mail\WelcomeMail;
use JohnDoe\BlogPackage\Models\Post;
use JohnDoe\BlogPackage\Tests\TestCase;
class WelcomeMailTest extends TestCase
{
/** @test */
public function it_sends_a_welcome_email()
{
Mail::fake();
$post = Post::factory()->create(['title' => 'Fake Title']);
Mail::assertNothingSent();
Mail::to('test@example.com')->send(new WelcomeMail($post));
Mail::assertSent(WelcomeMail::class, function ($mail) use ($post) {
return $mail->post->id === $post->id
&& $mail->post->title === 'Fake Title';
});
}
}
With this passing test, you can be sure that your package can now send e-mails.