Postmark email provider

Postmark provider implementing email.ProviderPort against the Postmark REST API.

Overview

Postmark is a transactional-only email service provider (ESP). Postmark refuses marketing and newsletter campaigns and runs dedicated IP pools for transactional traffic. That policy is what keeps the shared pools clean, since the traffic on them is uniform.

The provider uses Postmark's per-server token model. Each Postmark server is a logical sender (for example one for transactional mail, one for password resets) with its own stream and reputation. Sending needs only ServerToken. The optional AccountToken matters only when you call account-level admin endpoints.

You write almost no glue. Construct the provider, pass it to WithEmailProvider and WithDefaultEmailProvider, and the framework's email service, builder, and dispatcher take over. PostmarkProvider satisfies the email.ProviderPort interface, so it registers through the same options as every other email provider.

The provider is pure Go. It needs no build tag, no CGO, and no system libraries, so it runs in compiled builds and in interpreted dev mode (dev-i).

Rate limiting

NewPostmarkProvider always installs a token-bucket rate limiter. It allows 100 calls per second with a burst of 200, matching Postmark's documented limit for standard accounts. Send blocks on the limiter before each API call. The limiter is the same shared provider rate-limiter machinery used across email providers, so its behaviour is consistent.

Bulk sending

Postmark has no native bulk API. SupportsBulkSending reports false, and SendBulk sends each message with an individual Send call. Every message passes through the rate limiter. A batch with partial failures returns a MultiError that names each failed send.

Observability

The provider emits OpenTelemetry metrics with no setup on your part. email.provider.postmark.send.total counts send attempts and email.provider.postmark.send.duration records send latency in milliseconds. Both carry a status label (success or error) and a send_type label (single or bulk). All methods are safe for concurrent use.

Requirements

  • A Postmark account with at least one server set up. Generate a server token from the server's API Tokens tab.
  • A verified sender signature or domain matching FromEmail.
  • Network egress to api.postmarkapp.com.

Configuration

import (
    "context"
    "os"

    "piko.sh/piko/wdk/email/email_provider_postmark"
)

provider, err := email_provider_postmark.NewPostmarkProvider(ctx, email_provider_postmark.PostmarkProviderArgs{
    ServerToken:  os.Getenv("POSTMARK_SERVER_TOKEN"), // required; per-server sending token
    FromEmail:    "[email protected]",              // required; verified sender or domain
    AccountToken: "",                                 // optional; only for account-level admin calls
})
if err != nil {
    return err
}

Bootstrap

ssr := piko.New(
    piko.WithEmailProvider("postmark", provider),
    piko.WithDefaultEmailProvider("postmark"),
)

After registration, send through the email service. Call email.NewEmailBuilderFromDefault() to get a builder bound to the default provider, then chain recipients, subject, and body. See the Email API reference for the full builder.

Per-send Postmark options

The builder's ProviderOption(key, value) method passes Postmark-specific settings through to the adapter. The provider reads four keys.

  • tag. A string label for the message, used in Postmark's analytics.
  • track_opens. A bool that turns open tracking on or off. The provider tracks opens by default.
  • track_links. A string that selects link tracking (for example "HtmlAndText").
  • message_stream. A string that routes the message to a named Postmark stream.
builder, err := email.NewEmailBuilderFromDefault()
if err != nil {
    return err
}
err = builder.
    To("[email protected]").
    Subject("Welcome").
    BodyHTML("<p>Hi</p>").
    ProviderOption("message_stream", "outbound").
    ProviderOption("tag", "welcome").
    Do(ctx)

Tradeoffs

Postmark explicitly refuses marketing/newsletter traffic. That policy keeps their transactional reputation high. It also means you cannot use Postmark as a one-stop ESP if you also send campaigns. Pair it with a separate marketing tool when needed.

See also

Other email providers:

  • SendGrid, combined transactional and marketing.
  • SES, cheapest at scale if already on AWS.
  • Mailgun, strong EU presence, flexible routing rules.
  • Mailchimp Transactional, the former Mandrill.
  • SMTP, generic backend for self-hosted or vendor-neutral relays.
  • Gmail, Gmail SMTP with app passwords (dev / low-volume).

Framework docs:

External: