Aller au contenu
← Retour aux projets

Laravel Postmark

Laravel Postmark

#Laravel Postmark

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads License

A PHP/Laravel client for the Postmark REST API. Covers transactional email (single, templated and batch), templates, bounces, message search, outbound statistics, server details and suppressions through a simple, typed API built on Laravel's Http client.

#Features

  • Transactional email: send a single message, a templated message, or a batch of either
  • Templates: list, get, create, update, delete
  • Bounces: list with filters, get, raw dump, reactivate, delivery stats
  • Messages: search outbound and inbound, get message details
  • Stats: outbound overview, sends, bounces, opens, clicks, spam
  • Server: get the authenticated server's details
  • Suppressions: dump, create and delete per message stream
  • Throws PostmarkException (carrying Postmark's ErrorCode and error body) on any non-2xx response
  • Throws InvalidArgumentException before hitting the API when a required field is missing

#Installation

You can install the package via composer:

composer require jeffersongoncalves/laravel-postmark

Publish the config file:

php artisan vendor:publish --tag=postmark-config

Set your Postmark server token in .env:

POSTMARK_TOKEN=your-server-token

Find it under Servers > (your server) > API Tokens in your Postmark account.

#Configuration

// config/postmark.php
return [
    'api_url' => env('POSTMARK_API_URL', 'https://api.postmarkapp.com'),
    'token' => env('POSTMARK_TOKEN', ''),
    'message_stream' => env('POSTMARK_MESSAGE_STREAM', 'outbound'),
    'default_count' => env('POSTMARK_DEFAULT_COUNT', 50),
];

message_stream is applied to every send and suppression call that does not pass its own, and default_count is the page size used by the list endpoints.

#Usage

The package is resolved via the Postmark facade or by injecting JeffersonGoncalves\Postmark\Postmark. Each API group is exposed as a method returning a dedicated resource class; sending and the server endpoint live directly on the manager.

#Sending email

use JeffersonGoncalves\Postmark\Facades\Postmark;

Postmark::sendEmail(
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Welcome aboard',
    htmlBody: '<p>Hello!</p>',
);

// Several recipients (Postmark accepts up to 50 per message):
Postmark::sendEmail('sender@example.com', ['a@example.com', 'b@example.com'], 'Hi', textBody: 'Hi');

// Any other Postmark field goes in $options:
Postmark::sendEmail(
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Welcome aboard',
    htmlBody: '<p>Hello!</p>',
    options: [
        'Cc' => 'cc@example.com',
        'ReplyTo' => 'reply@example.com',
        'Tag' => 'welcome',
        'TrackOpens' => true,
        'TrackLinks' => 'HtmlAndText',
        'MessageStream' => 'broadcast',
    ],
);

#Sending with a template

An integer is sent as TemplateId, a string as TemplateAlias:

Postmark::sendEmailWithTemplate('sender@example.com', 'recipient@example.com', 'welcome', [
    'name' => 'Ada',
    'product_url' => 'https://example.com',
]);

Postmark::sendEmailWithTemplate('sender@example.com', 'recipient@example.com', 1234567);

#Sending a batch

Batches take raw Postmark message payloads; the configured message stream is applied to any message that does not set its own.

Postmark::sendBatch([
    ['From' => 'sender@example.com', 'To' => 'a@example.com', 'Subject' => 'Hi', 'TextBody' => 'Hi'],
    ['From' => 'sender@example.com', 'To' => 'b@example.com', 'Subject' => 'Hi', 'TextBody' => 'Hi'],
]);

Postmark::sendBatchWithTemplates([
    ['From' => 'sender@example.com', 'To' => 'a@example.com', 'TemplateAlias' => 'welcome', 'TemplateModel' => ['name' => 'Ada']],
]);

#Templates

Postmark::templates()->list();
Postmark::templates()->list(count: 10, offset: 0, type: 'Standard');
Postmark::templates()->get('welcome');
Postmark::templates()->create('Welcome', 'Welcome aboard', [
    'Alias' => 'welcome',
    'HtmlBody' => '<p>Hello {{name}}</p>',
    'TextBody' => 'Hello {{name}}',
]);
Postmark::templates()->update('welcome', ['Subject' => 'Welcome!']);
Postmark::templates()->delete('welcome');

#Bounces

Postmark::bounces()->list(['type' => 'HardBounce', 'inactive' => true]);
Postmark::bounces()->get(692560173);
Postmark::bounces()->dump(692560173);   // raw bounce source
Postmark::bounces()->activate(692560173); // reactivate the address
Postmark::bounces()->deliveryStats();

#Messages

Postmark::messages()->outbound(['tag' => 'welcome', 'status' => 'sent']);
Postmark::messages()->inbound(['recipient' => 'inbox@example.com']);
Postmark::messages()->get('0a129aee-e1cd-480d-b08d-4f48548ff48d');
Postmark::messages()->inboundDetails('e2ecbbfc-fe12-463d-b933-9fe22915106d');

#Stats

Postmark::stats()->overview();
Postmark::stats()->sends(tag: 'welcome', fromDate: '2026-01-01', toDate: '2026-01-31');
Postmark::stats()->bounces();
Postmark::stats()->opens();
Postmark::stats()->clicks();
Postmark::stats()->spam();

#Server

Postmark::server();

#Suppressions

Postmark::suppressions()->list();                    // configured stream
Postmark::suppressions()->list('broadcast');
Postmark::suppressions()->create('bounced@example.com');
Postmark::suppressions()->create(['a@example.com', 'b@example.com'], 'broadcast');
Postmark::suppressions()->delete('a@example.com');

#Error handling

use JeffersonGoncalves\Postmark\Exceptions\PostmarkException;

try {
    Postmark::sendEmail('sender@example.com', 'recipient@example.com', 'Hi', textBody: 'Hi');
} catch (PostmarkException $e) {
    $e->getMessage();  // Postmark's "Message"
    $e->getCode();     // Postmark's "ErrorCode", or the HTTP status when absent
    $e->errorBody();   // the full decoded error body
}

#Testing

composer test

#Changelog

Please see CHANGELOG for more information on what has changed recently.

#Contributing

Please see CONTRIBUTING for details.

#Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

#Credits

#License

The MIT License (MIT). Please see License File for more information.

Nouvelle version disponible.