Email

Postmark integration

Ahena works with your Postmark account and one of its servers: it adds your sending domain, lists the DKIM and Return-Path records it needs and asks Postmark to re-check them, creates message streams and authenticated webhooks, and keeps Sandbox servers out of production. Your app sends straight to Postmark through the same generated email code Ahena writes for Resend. Ahena isn't in the path.

What Ahena inspects

Read-only: inspecting and Doctor never change anything at Postmark.

  • Both tokens, the server and its delivery type (Live or Sandbox). Server API tokens in Postmark's responses are dropped, never returned.
  • Your sending domain's DKIM and Return-Path verification, with the exact records Postmark gives.
  • DMARC, through a public DNS-over-HTTPS lookup (no credentials).
  • Sender signatures, and whether email.from is on a verified domain or a confirmed signature.
  • Message streams (type, archived) and webhooks (URL, stream, triggers, whether basic auth is set; never the password or header values).
  • Whether your webhook route rejects a request without credentials.

What Ahena configures

You declare what you want in ahena.config.ts; ahena plan shows each change with its classification before anything is applied.

ChangeClassificationNotes
Add the sending domainCONFIRMATION_REQUIREDPublishing the DKIM TXT and Return-Path CNAME records Postmark returns is a manual DNS step; Doctor lists them.
Ask Postmark to re-check DKIM and Return-PathSAFEA DNS re-check only; changes no configuration.
Create a message streamCONFIRMATION_REQUIRED—
Create a webhook on a streamCONFIRMATION_REQUIREDPostmark doesn't sign webhooks, so Ahena sets HTTP basic auth with a generated password and stores the credentials encrypted as POSTMARK_WEBHOOK_USERNAME and POSTMARK_WEBHOOK_PASSWORD.
Turn on missing webhook triggers, or add basic auth to a webhook with no credentialsCONFIRMATION_REQUIREDTriggers are only ever turned on, and credentials you set are never replaced.

Refused outright:

  • Deleting domains, streams, webhooks or servers, or archiving streams.
  • Creating or changing servers; a Sandbox server can't become Live, so production needs a new Live server.
  • Webhook URLs that aren't public https or that embed credentials.

Generated code: src/ahena/email/index.ts (the same email.send and email.raw interface as Resend), src/ahena/providers/postmark.ts, .env.example.postmark and, with Next.js, a webhook route that checks the basic auth credentials and rejects requests without them.

How Ahena verifies

After every write, Ahena reads Postmark back. Each change ends in one of these states, and the plan's outcome says why:

  • VERIFIED: Ahena read the provider back and saw the desired state. The CLI shows ✓ only for VERIFIED.
  • APPLIED_UNVERIFIED: The provider accepted the change, but the re-read doesn't show it yet (after bounded polling), or the re-read failed.

Creates are read, matched (webhooks by URL and stream) and made only if absent, then read back, with full pagination of domains and sender signatures.

Webhooks are verified by existence: URL, stream, triggers and that basic auth is set are read back; the password is never compared or returned.

Domain verification honestly stays APPLIED_UNVERIFIED while DNS propagates.

If a request may have reached Postmark but the answer was lost, Ahena re-reads before deciding: done, safe to retry, or “check before retrying”.

What Doctor diagnoses

Key checks from ahena doctor. Each finding says why it matters, where, the impact and whether Ahena can fix it. The full list is in the Postmark docs.

CheckWhat it means
postmark.account / postmark.serverEach token works; which one was rejected if not.
postmark.server.deliveryA Sandbox server in production fails, with the manual steps to move to a Live server.
postmark.domain.dkim / .return_pathEach record's state, with the exact record to add (FAIL in production).
postmark.senderemail.from is on a DKIM-verified domain or a confirmed sender signature.
postmark.streamThe configured stream exists and isn't archived.
postmark.webhook / .authA webhook for the endpoint on the stream, with the triggers and basic auth.
postmark.webhook.endpointOne POST without credentials to your route: rejected is good; a 2xx means it doesn't check basic auth.

More on findings, health and continuous checks: Doctor.

Approvals

Postmark changes here are classified CONFIRMATION_REQUIRED and SAFE. Every change is planned and shown as a diff first. Ahena itself enforces who can approve it:

  • SAFE changes are applied without asking.
  • In production, every other change needs approval in the Ahena dashboard, signed in, by an admin.
  • In other environments, CONFIRMATION_REQUIRED changes are approved in the CLI; BILLABLE and DESTRUCTIVE changes always need the dashboard.
  • MANUAL steps are never applied by Ahena.

--yes and --allow-billable don't replace a dashboard approval. See approvals for how it works and why the browser.

Manual steps

These are MANUAL: Ahena never does them. It lists them with the exact steps when they apply.

  • Publish the DKIM TXT and Return-Path CNAME records Doctor lists, then run ahena configure postmark to have them re-checked.
  • Production on a Sandbox server: create a Live server in Postmark and reconnect with its Server API token.
  • After deploying the webhook route with its credentials, send a test from the webhook's page in Postmark.

Credentials and permissions

NameSecretNotes
POSTMARK_ACCOUNT_TOKENYesThe Account API token (account owners and admins): domains, DKIM, Return-Path and sender signatures.
POSTMARK_SERVER_TOKENYesA Server API token for the one server this environment sends through: message streams and webhooks.
POSTMARK_SERVER_IDNoOptional. The server the token belongs to; Ahena checks they match.
POSTMARK_WEBHOOK_USERNAME / POSTMARK_WEBHOOK_PASSWORDYesCreated by Ahena with the webhook. Read them back with ahena env reveal <environment> POSTMARK_WEBHOOK_PASSWORD (always audited).

Least privilege

  • Postmark tokens have no scopes, so Ahena checks only that each token works, and says so.
  • Generate separate tokens for Ahena (a server and the account can each have up to three), and give your app only its server's token.

Each credential Ahena stores gets its own key and is envelope-encrypted, bound to the environment. See security.

Workflow example

Connect, check, plan, then apply. Placeholders (…) stand for your own values.

  1. POSTMARK_ACCOUNT_TOKEN=… POSTMARK_SERVER_TOKEN=… ahena connect postmark -e production

    Connect with both tokens.

  2. ahena doctor -e production

    Check the server, domain, DKIM, Return-Path, DMARC, stream and webhook.

  3. ahena plan -e production

    See the domain, stream and webhook changes.

  4. ahena apply -e production

    Approve and apply; the webhook credentials are stored encrypted.

  5. ahena generate postmark -e production --framework nextjs

    Write the email adapter and the webhook route.

Verification status

Beta

Available in beta. Every capability is validated by Ahena's automated provider contract and conformance tests; verification against the real service is next.

How Postmark is tested
  • Postmark is tested against a simulated version of its API: both token types, ErrorCode errors, count/offset pagination, the read-back after each write and idempotent re-apply.
  • It hasn't been run against the real Postmark API yet. Whether Postmark's webhook test deliveries carry the basic auth credentials is taken from the docs, not observed.
  • The generated webhook route is typechecked against the real postmark SDK and run in tests; the email adapter is typechecked.

The providers overview explains Ahena's testing methodology and what has been verified for every provider.

Limitations

  • Ahena doesn't delete or archive anything, rotate DKIM keys, or create servers.
  • ahena configure cloudflare --records-from reads only Resend today; Postmark's DNS records are published by hand.
  • Account approval, suppression lists, templates and inbound processing are out of scope.

Disconnecting

ahena disconnect postmark removes the stored tokens; Postmark has no revoke API, so delete Ahena's tokens in Postmark. Servers, domains, streams and webhooks are untouched.