Help us shape the future of Go! Take the 2026 Go Developer Survey

postmark

package module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 25, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

README

Postmark plugin

Sends your app's email through Postmark, and keeps a list of the addresses Postmark stopped sending to (hard bounces, spam complaints, unsubscribes), so your app can stop emailing them too.

Install

From your project's directory:

go tool anetos add anetos.dev/anetos/plugins/postmark
go run . migrate

It adds:

Settings POSTMARK_WEBHOOK_USER, POSTMARK_WEBHOOK_PASSWORD: the basic auth of the webhook URL
Route POST /postmark/webhook (postmark.webhook), which queues each event
Job postmark:webhook, run by the app's queue workers, which updates the list
Table postmark_suppressions (migration set postmark)
Commands postmark:suppressions (list), postmark:unsuppress <email>

go run . plugin:list shows them.

Send email through Postmark

The mail transport is a mailer driver, which your setup passes to mailer.New (installing the plugin doesn't change your mailer):

// illustrative
m, err := mailer.New(app, postmark.Driver())
MAIL_DRIVER=postmark
MAIL_POSTMARK_TOKEN=…          # the server API token
MAIL_POSTMARK_STREAM=outbound  # the default

Receive Postmark's webhooks

In Postmark, add a webhook to https://USER:PASSWORD@example.com/postmark/webhook for the Bounce, Spam Complaint and Subscription Change events, with the user and password of your POSTMARK_WEBHOOK_* settings. Without them, the endpoint refuses every request. Then check an address before emailing it with postmark.Suppressed(ctx, email).

More

  • Plugins: installing and removing plugins
  • Send email: the mailer
  • go doc anetos.dev/anetos/plugins/postmark

Documentation

Overview

Package postmark is the Postmark plugin: a transport that sends the mailer package's emails with Postmark's API (https://postmarkapp.com), and webhooks that keep a list of the addresses Postmark stopped sending to (Plugin).

m, err := mailer.New(app, postmark.Driver())

Settings: MAIL_DRIVER=postmark, MAIL_POSTMARK_TOKEN (a server API token; POSTMARK_API_TEST checks requests without sending), and MAIL_POSTMARK_STREAM (the message stream, default "outbound"). The plugin's are POSTMARK_WEBHOOK_USER and POSTMARK_WEBHOOK_PASSWORD.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Driver

func Driver(opts ...Option) mailer.Driver

Driver is the transport's driver (MAIL_DRIVER=postmark).

func Plugin

func Plugin() ext.Plugin

Plugin returns the Postmark plugin: an endpoint for Postmark's webhooks, which records the addresses Postmark stops sending to (hard bounces, spam complaints, unsubscribes) in a suppression list, so the app can stop emailing them too (Suppressed). Install it with

anetos add anetos.dev/anetos/plugins/postmark

It adds:

  • settings POSTMARK_WEBHOOK_USER and POSTMARK_WEBHOOK_PASSWORD, the basic auth credentials of the webhook URL you set in Postmark;
  • the route POST /postmark/webhook (postmark.webhook), which queues each event;
  • the job postmark:webhook, which updates the list;
  • the table postmark_suppressions (migration set postmark);
  • the commands postmark:suppressions and postmark:unsuppress.

In Postmark, add a webhook to https://USER:PASSWORD@example.com/postmark/webhook for the Bounce, Spam Complaint and Subscription Change events.

func Suppressed

func Suppressed(ctx context.Context, email string) (bool, error)

Suppressed reports whether Postmark stopped sending to email (its webhooks said so), for apps that check before sending:

if bad, err := postmark.Suppressed(ctx, user.Email); err != nil || bad { … }

Types

type Config

type Config struct {
	// Token is the Postmark server's API token. MAIL_POSTMARK_TOKEN.
	Token anetos.Secret `env:"MAIL_POSTMARK_TOKEN"`
	// Stream is the message stream emails are sent on.
	// MAIL_POSTMARK_STREAM, default outbound.
	Stream string `env:"MAIL_POSTMARK_STREAM" default:"outbound"`
}

Config is the transport's settings.

type Error

type Error struct {
	// Status is the HTTP status.
	Status int
	// Code is Postmark's error code (300: invalid email request, 406:
	// inactive recipient, …).
	Code int
	// Message is Postmark's explanation.
	Message string
}

Error is an error response of Postmark's API.

func (*Error) Error

func (e *Error) Error() string

Error implements error.

type Option

type Option func(*Transport)

Option configures a Transport.

func BaseURL deprecated

func BaseURL(u string) Option

BaseURL is WithBaseURL.

Deprecated: Use WithBaseURL; BaseURL is removed in v0.6.

func HTTPClient deprecated

func HTTPClient(c *http.Client) Option

HTTPClient is WithHTTPClient.

Deprecated: Use WithHTTPClient; HTTPClient is removed in v0.6.

func Stream deprecated

func Stream(s string) Option

Stream is WithStream.

Deprecated: Use WithStream; Stream is removed in v0.6.

func WithBaseURL added in v0.5.0

func WithBaseURL(u string) Option

WithBaseURL sets the API's URL, for tests. Default https://api.postmarkapp.com.

func WithHTTPClient added in v0.5.0

func WithHTTPClient(c *http.Client) Option

WithHTTPClient sets the HTTP client. Default: one with a 30-second timeout.

func WithStream added in v0.5.0

func WithStream(s string) Option

WithStream sets the message stream. Default "outbound".

type Settings

type Settings struct {
	// WebhookUser is the user name of the basic auth Postmark sends with
	// webhooks (set in the webhook's URL). Without it and the password,
	// the webhook endpoint refuses every request.
	WebhookUser string `env:"POSTMARK_WEBHOOK_USER"`
	// WebhookPassword is the webhook's password.
	WebhookPassword anetos.Secret `env:"POSTMARK_WEBHOOK_PASSWORD"`
}

Settings are the plugin's settings.

type Suppression

type Suppression struct {
	db.Model
	// Email is the address, in lower case.
	Email string `db:"email" json:"email"`
	// RecordType is the webhook event: Bounce, SpamComplaint or
	// SubscriptionChange.
	RecordType string `db:"record_type" json:"record_type"`
	// Reason is Postmark's description: the bounce type, the
	// unsubscribe's origin.
	Reason string `db:"reason" json:"reason"`
	// MessageID is the Postmark ID of the email the event is about.
	MessageID string `db:"message_id" json:"message_id"`
}

Suppression is an address Postmark stopped sending to.

func (Suppression) TableName

func (Suppression) TableName() string

TableName implements db.Tabler.

type Transport

type Transport struct {
	// contains filtered or unexported fields
}

Transport sends emails with Postmark's API.

func NewTransport

func NewTransport(token string, opts ...Option) *Transport

NewTransport returns a transport sending with the server token token.

func (*Transport) Send

func (t *Transport) Send(ctx context.Context, m *mailer.Outgoing) error

Send implements mailer.Transport. Postmark's refusals (422, 401, 403, 413) are permanent errors (queue.Permanent), except error code 405 (the account can't send now: out of credits); rate limits (429) and server errors aren't either. Postmark gives the email a Message-ID of its own.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL