Send PocketBase email through the Groundmail transactional email API instead of SMTP.
Verification emails, password resets, OTPs and your own sends all go through Groundmail.
Register hooks OnMailerSend, so every email the app sends goes through Groundmail and PocketBase's SMTP settings are not used. Set the sender under Settings → Mail settings in the dashboard, on a domain you have verified in Groundmail.
m, err := groundmailpb.New(groundmailpb.Options{})
if err != nil {
return err
}
return m.Send(&mailer.Message{
From: mail.Address{Name: "Acme", Address: "noreply@yourdomain.com"},
To: []mail.Address{{Address: "user@example.com"}},
Subject: "Your receipt",
HTML: "<p>Thanks for your purchase.</p>",
})
Attachments and inline attachments are sent with the message; inline files are referenced by name (cid:logo.png).
Contributing
Found a bug or want something added? Open an issue. This code is published here on each release, so we port fixes rather than merging pull requests directly.
Why Groundmail
Our own mail servers and IP space. Your password resets and receipts don't share a pool with bulk marketing senders.
Transactional email only. No newsletters or cold outreach on the platform, which keeps the sending reputation clean.
Start free. 3,000 emails a month on the Free plan; Pro is 50,000 emails for $20/month. Dedicated IPs on Scale.
Built for code and for agents. REST API, SMTP, SDKs for Node, Python, Go, PHP and Ruby, a CLI, and an MCP server for Claude, ChatGPT and Cursor.
Register binds the app's OnMailerSend hook, so password resets, email
verification, OTPs and every app.NewMailClient().Send call go through
Groundmail. Mailer also implements PocketBase's mailer.Mailer interface for
direct use.
type Options struct {
// APIKey is a Groundmail API key (gm_…). Defaults to GROUNDMAIL_API_KEY. APIKey string// BaseURL overrides the API base URL. BaseURL string// HTTPClient overrides the HTTP client. HTTPClient *http.Client
}