Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Postmark Mailer Laravel Package

symfony/postmark-mailer

Symfony Mailer bridge for Postmark. Send email via Postmark using SMTP or the API by setting a postmark DSN (postmark+smtp://TOKEN@default or postmark+api://TOKEN@default). Provides seamless Postmark integration in Symfony apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Package Add to composer.json:

    composer require symfony/postmark-mailer
    
  2. Configure .env Use either SMTP or API transport:

    # SMTP Transport (recommended for transactional emails)
    MAIL_MAILER=postmark
    MAILER_DSN=postmark+smtp://YOUR_POSTMARK_SERVER_TOKEN@default
    
    # API Transport (alternative)
    MAILER_DSN=postmark+api://YOUR_POSTMARK_SERVER_TOKEN@default
    
  3. First Use Case: Send a Test Email Leverage Laravel’s Mail facade or Symfony’s MailerInterface:

    use Illuminate\Support\Facades\Mail;
    use App\Mail\TestEmail;
    
    Mail::to('user@example.com')->send(new TestEmail());
    

    Or via Symfony’s Mailer:

    $mailer = $container->get(MailerInterface::class);
    $email = (new Email())
        ->from('noreply@example.com')
        ->to('user@example.com')
        ->subject('Test Email')
        ->text('Hello, this is a test!');
    $mailer->send($email);
    
  4. Verify in Postmark Dashboard Check the Postmark web interface for delivered emails and analytics.


Implementation Patterns

Core Workflows

1. Transactional Emails (High Priority)

  • Pattern: Use SMTP transport for low-latency, high-reliability delivery (e.g., password resets, OTPs).
  • Example:
    // Configure in config/mail.php
    'postmark' => [
        'transport' => 'postmark+smtp://token@default',
        'options' => [
            'host' => 'smtp.postmarkapp.com',
            'port' => 587,
            'encryption' => 'tls',
        ],
    ];
    
    // Send via Laravel Mail
    Mail::to($user->email)->send(new PasswordResetMail($token));
    

2. Marketing Campaigns (Analytics-Driven)

  • Pattern: Use API transport for Postmark’s templates and tracking.
  • Example:
    // Custom Symfony Mailer transport in Laravel
    $mailer = app(MailerInterface::class);
    $email = (new Email())
        ->from('marketing@example.com')
        ->to('user@example.com')
        ->subject('Summer Sale')
        ->html(view('emails.promo'))
        ->addHeader('X-Postmark-Send-With', 'PostmarkAPI'); // Force API transport
    $mailer->send($email);
    

3. Inbound Email Parsing (Webhooks)

  • Pattern: Use Postmark’s Inbound Parsing with Laravel’s Http client.
  • Example:
    // Route webhook to Laravel controller
    Route::post('/postmark/webhook', [PostmarkWebhookController::class, 'handle']);
    
    // Controller logic
    public function handle(Request $request) {
        $payload = $request->json()->all();
        if ($payload['MessageID'] && $payload['To']) {
            // Parse and process inbound email
            $this->processInboundEmail($payload);
        }
    }
    

4. Queue-Based Async Sends

  • Pattern: Dispatch emails to Laravel queues for background processing.
  • Example:
    // Dispatch a queued mailable
    Mail::to($user->email)->queue(new WelcomeEmail($user));
    
    // Configure queue in config/mail.php
    'postmark' => [
        'queue' => 'default', // Use Laravel queues
    ];
    

Integration Tips

  1. Laravel-Symfony Bridge

    • Create a custom transport to adapt Symfony’s PostmarkTransport for Laravel:
      use Symfony\Component\Mailer\Transport\TransportInterface;
      use Symfony\Component\Mailer\Transport\Dsn;
      
      class PostmarkTransport extends \Symfony\Component\Mailer\Transport\PostmarkTransport
      {
          public function __construct(Dsn $dsn, array $options = [])
          {
              parent::__construct($dsn, $options);
          }
      }
      
    • Register in AppServiceProvider:
      public function register()
      {
          $this->app->singleton(TransportInterface::class, function ($app) {
              $dsn = new Dsn(config('mail.postmark.transport'));
              return new PostmarkTransport($dsn, config('mail.postmark.options'));
          });
      }
      
  2. Postmark Templates

    • Use Postmark’s template system for dynamic content:
      $email = (new Email())
          ->from('noreply@example.com')
          ->to('user@example.com')
          ->subject('Welcome!')
          ->html(view('emails.welcome', ['user' => $user]))
          ->addHeader('X-Postmark-Template-ID', '12345'); // Your Postmark template ID
      
  3. Error Handling

    • Extend Symfony’s TransportException for Laravel’s exception handler:
      try {
          $mailer->send($email);
      } catch (\Symfony\Component\Mailer\Exception\TransportException $e) {
          report($e); // Log via Laravel's reporting
          throw new \Exception('Failed to send email: ' . $e->getMessage());
      }
      
  4. Testing

    • Use Symfony’s TestMailer or Laravel’s MailFake:
      // Laravel test example
      public function test_email_sends()
      {
          Mail::fake();
          Mail::to('user@example.com')->send(new TestEmail());
          Mail::assertSent(TestEmail::class);
      }
      

Gotchas and Tips

Pitfalls

  1. SMTP vs. API Transport Quirks

    • SMTP: Faster for bulk sends but may hit rate limits (Postmark’s default: 100 emails/second).
      • Fix: Use API transport for high-volume sends or adjust rate limits in Postmark settings.
    • API: Slower per-email but supports templates and tracking.
      • Fix: Cache API responses for static templates.
  2. Date Header Dropped in API Transport

    • Postmark’s API transport automatically removes the Date header (as per #60256).
      • Workaround: Manually add it if required:
        $email->addHeader('Date', (new \DateTime())->format('r'));
        
  3. Attachment CID Issues

    • If using inline attachments (CIDs), ensure they’re properly set:
      $email->attachFromPath($path)
            ->if(function ($message) {
                $message->getHeaders()->addTextHeader('Content-ID', '<unique-id>');
            });
      
      • Debug: Check Postmark’s raw email source in the dashboard for missing CIDs.
  4. Payload Too Large Errors

    • Postmark API has a 10MB payload limit. Large emails (e.g., with attachments) may fail.
      • Fix: Use SMTP transport for large files or compress attachments.
  5. Webhook IP Allowlist

    • Postmark’s Inbound Parsing webhooks require IP allowlisting.
      • Tip: Use Postmark’s default IPs or whitelist your server’s IP in Postmark settings.

Debugging

  1. Enable Verbose Logging Configure Symfony’s logger in config/mail.php:

    'postmark' => [
        'options' => [
            'debug' => env('MAIL_DEBUG', false),
        ],
    ];
    
    • Check Laravel logs (storage/logs/laravel.log) for transport errors.
  2. Postmark API Debugging

    • Use Postmark’s API inspector to validate payloads:
      curl -X POST https://api.postmarkapp.com/email \
           -H "X-Postmark-Server-Token: YOUR_TOKEN" \
           -H "Content-Type: application/json" \
           -d '{"From": "sender@example.com", "To": "recipient@example.com", "Subject": "Test", "HtmlBody": "<p>Hello</p>"}'
      
  3. Common Errors and Fixes

    Error Cause Solution
    Invalid Server Token Wrong MAILER_DSN token Verify .env and Postmark account.
    Payload Too Large Email > 10MB Use SMTP or compress attachments.
    Date header missing API transport quirk Manually add Date header.
    Webhook IP not allowed Missing IP allowlist Wh
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
besmartand-pro/php-quality-config
sentix/ai-chatbot
codifyo/ts-generator-bundle
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor