nette/mail
Lightweight PHP mailer from the Nette framework: compose and send emails with SMTP support, MIME messages, attachments, HTML/text bodies, and headers. Sensible defaults, easy integration, and good testability for apps and services.
Install the package:
composer require nette/mail
Configure in config/mail.php (extend Laravel’s defaults):
'mailers' => [
'nette' => [
'transport' => 'smtp',
'host' => env('MAIL_HOST'),
'port' => env('MAIL_PORT'),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'encryption' => env('MAIL_ENCRYPTION'),
'dkim' => [
'domain' => env('MAIL_DKIM_DOMAIN'),
'selector' => env('MAIL_DKIM_SELECTOR'),
'privateKey' => env('MAIL_DKIM_PRIVATE_KEY'),
],
'debugger' => env('MAIL_DEBUGGER', false), // New: Enable MailTracy integration
'redirect' => env('MAIL_REDIRECT', null), // New: Interceptor redirect address
],
],
First use case: Send a simple HTML email with embedded images using the new HtmlComposer:
use Nette\Mail\Message;
use Nette\Mail\SendmailMailer;
use Nette\Mail\HtmlComposer;
$mailer = new SendmailMailer();
$message = new Message();
// Use HtmlComposer for pre-processing
$composer = new HtmlComposer();
$html = $composer->inlineCss('<p>Hello! <img src="cid:image1"></p>')
->embedImages(base_path('images'))
->getHtml();
$message->setFrom('sender@example.com')
->addTo('recipient@example.com')
->setSubject($composer->extractSubject($html)) // Auto-extracts <title>
->setHtmlBody($html)
->addInlinePart($mailer->createAttachment(file_get_contents('image.png'), 'image1.png'));
$mailer->send($message);
Nette\Mail\SendmailMailer for local testing and Nette\Mail\SmtpMailer for production.MAIL_REDIRECT=dev@example.com to .env to redirect all emails during development.MAIL_DEBUGGER=true to view sent emails in the Tracy Bar panel.use Nette\Mail\HtmlComposer;
$composer = new HtmlComposer();
$html = $composer->inlineCss('<p>Styled content</p>')
->embedImages(base_path('assets'))
->getHtml();
// Auto-generates plain-text alternative
$message->setHtmlBody($html)
->setTextBody($composer->generatePlainText());
// Configure in config/mail.php (see above)
// All emails sent to any address will be redirected to dev@example.com
// Original recipients are preserved in X-Original-To headers
// Auto-registered when:
// 1. MAIL_DEBUGGER=true in config
// 2. Interceptor is active (MAIL_REDIRECT set)
// View sent emails in Tracy Bar panel (Tracy Debugger required)
use Nette\Mail\FallbackMailer;
use Nette\Mail\Interceptor;
$fallbackMailer = new FallbackMailer([
new Interceptor(new SmtpMailer($smtpConfig), 'dev@example.com'),
new SendmailMailer(),
]);
Extend Laravel’s Mailer with Interceptor:
use Nette\Mail\Interceptor;
use Nette\Mail\SmtpMailer;
class NetteMailer extends \Illuminate\Mail\Mailer
{
public function send(NetteMessage $message, $to, $subject = null)
{
$netteMessage = new Message();
$netteMessage->setFrom($message->from)
->addTo($to)
->setSubject($subject ?? $message->subject);
// Use Interceptor for dev mode
$mailer = env('MAIL_REDIRECT')
? new Interceptor(new SmtpMailer($this->getSmtpConfig()), env('MAIL_REDIRECT'))
: new SmtpMailer($this->getSmtpConfig());
$mailer->send($netteMessage);
}
}
Use with Laravel Notifications and HtmlComposer:
use Illuminate\Notifications\Notification;
use Nette\Mail\HtmlComposer;
class EmailNotification extends Notification
{
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
$composer = new HtmlComposer();
$html = $composer->inlineCss('<h1>Hello!</h1>')
->embedImages(public_path('images'))
->getHtml();
return (new Message())
->setHtmlBody($html)
->setTextBody($composer->generatePlainText());
}
}
Queue Emails with Interceptor:
use Nette\Mail\Interceptor;
use Illuminate\Support\Facades\Bus;
Bus::dispatch(function () use ($mailer) {
$interceptor = new Interceptor($mailer, 'dev@example.com');
$interceptor->send($message);
});
$composer = new HtmlComposer();
$html = $composer->inlineCss($dynamicHtmlTemplate)
->embedImages(base_path('dynamic_assets'))
->getHtml();
// Reuse across multiple messages
$message1->setHtmlBody($composer->getHtml());
$message2->setHtmlBody($composer->inlineCss($anotherTemplate)->getHtml());
$mailer = app()->environment('local')
? new Interceptor(new SmtpMailer($config), 'dev@example.com')
: new SmtpMailer($config);
// Disable MailTracy globally
config(['mail.debugger' => false]);
// Or configure per-mailer
$mailer = new Interceptor(new SmtpMailer($config), 'dev@example.com');
$mailer->setDebugger(false);
Interceptor Header Conflicts:
X-* headers may conflict with Interceptor’s X-Original-* headers.$message->addHeader('X-Custom', 'value');
$interceptor->send($message); // Preserves custom headers
HtmlComposer CSS Inlining Limitations:
@media queries) may not inline perfectly.MailTracy Tracy Dependency:
composer require nette/tracy
Interceptor Redirect Loop:
$interceptor = new Interceptor($mailer, 'dev@example.com');
if ($message->getFrom() === 'dev@example.com') {
$mailer->send($message); // Bypass interceptor
} else {
$interceptor->send($message);
}
HtmlComposer Image Embedding:
embedImages() may break in production.$composer->embedImages(base_path('storage/app/public/images'));
Inspect Interceptor Headers:
$message->onSend[] = function ($message) {
dd($message->getHeaders());
};
MailTracy Panel Debugging:
MAIL_DEBUGGER=true).HtmlComposer Output Validation:
$composer = new HtmlComposer();
$html = $composer->inlineCss($html);
dd($composer->getErrors()); // Check for CSS inlining issues
Interceptor Logs:
$interceptor = new Interceptor($mailer, 'dev@example.com');
$
How can I help you explore Laravel packages today?