openbuildings/postmark
Laravel package for integrating Postmark email delivery into your app. Provides a simple mail driver and configuration for sending transactional emails via Postmark’s API, fitting neatly into Laravel’s mail system with minimal setup.
Installation Add the package via Composer:
composer require openbuildings/postmark
Configuration Publish the config file:
php artisan vendor:publish --provider="OpenBuildings\Postmark\PostmarkServiceProvider"
Update .env with your Postmark API key:
POSTMARK_API_KEY=your_api_key_here
First Use Case
Replace Laravel's default Swift Mailer transport in config/mail.php:
'transport' => [
'driver' => 'postmark',
],
Send a test email:
Mail::raw('Test email body', function ($message) {
$message->to('recipient@example.com')
->subject('Test Subject');
});
config/postmark.php (default settings)app/Providers/AppServiceProvider.php (if customizing mail transport binding)Use Laravel's Mail facade as usual:
Mail::to('user@example.com')->send(new WelcomeEmail($user));
Attach Postmark-specific metadata or headers:
Mail::raw('Content', function ($message) {
$message->to('user@example.com')
->subject('Subject')
->withSwiftMessage(function ($swiftMessage) {
$swiftMessage->getHeaders()->addTextHeader('X-Metadata', 'key=value');
});
});
Enable Postmark's tracking features via config:
'options' => [
'track_opens' => true,
'track_links' => true,
],
Use Postmark's batch API for high-volume emails:
Mail::batch(['user1@example.com', 'user2@example.com'])
->send(new NewsletterEmail());
Combine with Laravel's default transport for fallback:
'transport' => [
'driver' => 'failover',
'options' => [
'primary' => 'postmark',
'secondary' => 'smtp',
],
],
Extend Mailable or Notification classes to inject Postmark-specific data:
public function build()
{
return $this->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('X-Custom-Header', 'value');
});
}
Queue emails for async sending (Postmark supports this natively):
Mail::queue(new OrderConfirmation($order));
Monitor Postmark queue jobs in Horizon for debugging.
Use Laravel's .env files to switch keys per environment (e.g., POSTMARK_API_KEY_STAGING).
API Key Exposure
.env or hardcode keys in code.env() helper or config caching.Rate Limits
'options' => [
'retry' => true,
'retry_delay' => 30, // seconds
],
HTML vs. Text Emails
setBody() includes both:
$message->setBody('HTML content', 'text/html')
->setBody('Plain text fallback', 'text/plain');
Attachment Size Limits
if ($file->getSize() > 26 * 1024 * 1024) {
throw new \Exception('File too large for Postmark');
}
Debugging Failed Emails
config/mail.php:
'log' => env('MAIL_LOG', true),
Enable Verbose Logging
Add to config/postmark.php:
'debug' => env('APP_DEBUG', false),
Inspect Raw Swift Message
Use a MailMacro to log the Swift message before sending:
Mail::macro('logSwiftMessage', function ($callback) {
$callback(Mail::getSwiftMessage());
});
Test with Postmark's Sandbox Use the Postmark sandbox mode (enabled via API key) to test without sending real emails.
Custom Transport Binding
Override the transport binding in AppServiceProvider:
public function register()
{
$this->app->bind(\Swift_Transport::class, function ($app) {
return new \OpenBuildings\Postmark\PostmarkTransport(
$app['config']['postmark.api_key'],
$app['config']['postmark.options']
);
});
}
Event Listeners
Listen for mail.sent events to log or process Postmark-specific data:
Mail::sent(function ($message) {
if ($message->getSwiftMessage()->getHeaders()->get('X-Metadata')) {
// Handle Postmark metadata
}
});
Middleware for Headers Create middleware to inject Postmark headers globally:
public function handle($request, Closure $next)
{
Mail::macro('addPostmarkHeader', function ($key, $value) {
Mail::getSwiftMessage()->getHeaders()->addTextHeader($key, $value);
});
return $next($request);
}
Testing Use Postmark's API mocking in PHPUnit:
$this->partialMock(\OpenBuildings\Postmark\PostmarkTransport::class, ['send']);
How can I help you explore Laravel packages today?