frootbox / mail
Frootbox Mail Library
Requires
- php: >=8.0
- ext-curl: *
- frootbox/config: ^0.0.9 || ^1.0
- phpmailer/phpmailer: 6.6.*
README
Small mail abstraction around PHPMailer.
The package provides an Envelope object for message data and transport classes for SMTP or local mail()/sendmail delivery.
Requirements
- PHP 8.0 or newer
ext-curlphpmailer/phpmailerfrootbox/config
Installation
composer require frootbox/mail
Configuration
Transports expect a Frootbox\Config\Config instance. A config file can return a PHP array:
<?php return [ 'mail' => [ 'defaults' => [ 'from' => [ 'address' => 'noreply@example.com', 'name' => 'Example App', ], ], 'smtp' => [ 'host' => 'smtp.example.com', 'username' => 'smtp-user', 'password' => 'smtp-password', 'secure' => 'tls', 'port' => 587, 'debug' => false, ], ], ];
Load it like this:
use Frootbox\Config\Config; $config = new Config(__DIR__ . '/config.php');
Sending Via SMTP
use Frootbox\Config\Config; use Frootbox\Mail\Attachment; use Frootbox\Mail\Envelope; use Frootbox\Mail\Transports\Smtp; require __DIR__ . '/vendor/autoload.php'; $config = new Config(__DIR__ . '/config.php'); $envelope = new Envelope(); $envelope->setSubject('Welcome'); $envelope->setBodyHtml('<h1>Hello</h1><p>Thanks for signing up.</p>'); $envelope->addTo('person@example.com', 'Jane Person'); $envelope->addBcc('archive@example.com'); $envelope->setReplyTo('support@example.com', 'Support Team'); $envelope->addAttachment(new Attachment(__DIR__ . '/terms.pdf', 'terms.pdf')); $transport = new Smtp($config); $transport->send($envelope);
You can override SMTP settings for one transport instance:
$transport = new Smtp($config); $transport->setOverrideSettings([ 'host' => 'smtp.other-provider.com', 'username' => 'other-user', 'password' => 'other-password', 'secure' => 'tls', 'port' => 587, ]); $transport->send($envelope);
Sending Via Localhost
Use Localhost when the server is configured to send mail via PHP's local mail transport:
use Frootbox\Config\Config; use Frootbox\Mail\Envelope; use Frootbox\Mail\Transports\Localhost; require __DIR__ . '/vendor/autoload.php'; $config = new Config(__DIR__ . '/config.php'); $envelope = new Envelope(); $envelope->setSubject('Local test'); $envelope->setBodyHtml('<p>Hello from localhost.</p>'); $envelope->addTo('person@example.com'); $transport = new Localhost($config); $transport->send($envelope);
Custom From Address
Both transports use mail.defaults.from.* from the config by default. Override it per transport instance with setFrom():
$transport->setFrom('billing@example.com', 'Billing Team'); $transport->send($envelope);
Inline Images
The SMTP transport can fetch image URLs from the HTML body and embed them as CID attachments:
$envelope->setBodyHtml('<p><img src="https://example.com/logo.png" alt="Logo"></p>'); $transport->send($envelope, [ 'inlineImages' => true, ]);
Images whose src already starts with cid: are skipped.
Archiving Sent Messages
The built-in Smtp and Localhost transports keep the complete MIME source of the last sent message. This can be stored as an .eml file for audits, customer support, or external documentation.
$transport = new Smtp($config); $transport->send($envelope); $mimeMessage = $transport->getLastMimeMessage(); if ($mimeMessage !== null) { file_put_contents(__DIR__ . '/archive/welcome.eml', $mimeMessage); }
The MIME message is generated from PHPMailer immediately before delivery, so it includes headers, recipients, the rendered HTML body, embedded images, and attachments. getLastMimeMessage() returns null before the first successful send or when a custom transport does not support MIME archiving.
Envelope API
Common methods:
setSubject(string $subject): voidsetBodyHtml(string $html): voidaddTo(string $address, ?string $name = null): voidaddBcc(string $address, ?string $name = null): voidsetReplyTo(?string $address = null, ?string $name = null): voidaddAttachment(Attachment $attachment): voidclearTo(): voidclearBcc(): voidclearReplyTo(): void
Attachment accepts a filesystem path and an optional display name:
$envelope->addAttachment(new Attachment('/path/to/report.pdf')); $envelope->addAttachment(new Attachment('/path/to/report.pdf', 'monthly-report.pdf'));
Custom Transports
Custom transports should implement Frootbox\Mail\Transports\Interfaces\TransportInterface:
use Frootbox\Mail\Envelope; use Frootbox\Mail\Transports\Interfaces\TransportInterface; final class LogTransport implements TransportInterface { public function send(Envelope $envelope, array $parameters = []): void { // Deliver or record the envelope. } public function setFrom(string $address, ?string $name = null): void { // Store sender data for later use. } }
If a custom transport can expose the raw MIME source of the last sent message, it should also implement Frootbox\Mail\Transports\Interfaces\MimeMessageAwareTransportInterface.
License
GPL-3.0-only. See LICENSE.