Documentation for agents: an index at /llms.txt, every docs page in one file at /llms-full.txt, and Markdown for any docs page by adding .md to its URL.

Effect KitEmails

Postmark

Send email through Postmark with the @effect-kit/emails/postmark Layer.

The @effect-kit/emails/postmark subpath sends messages through Postmark and provides the Email service.

Installation

npm install @effect-kit/emails effect postmark@5.1.0

The SDK is a pinned optional peer. It is needed only when you import this subpath.

Setup

Postmark.layerConfig() reads these variables:

VariableRequiredValue
POSTMARK_SERVER_TOKENyesServer API token

Example (Sending a Message With Postmark)

import { , ,  } from "effect";
import {  } from "@effect-kit/emails";
import * as  from "@effect-kit/emails/postmark";

const  = .().(
  .(.(.())),
);

const  = .(function* () {
  const  = yield* ;
  return yield* .({
    : "hello@example.com",
    : "ada@example.com",
    : "Welcome",
    : "Your account is ready.",
  });
});

.(.(.()));

Use a from address your Postmark account is allowed to send from.

Options

Postmark.layer takes these options. layerConfig builds the same object from a Config.

Prop

Type

Capabilities

Postmark reports this in email.capabilities:

TextHTMLBothSender nameCcBccReply-toHeadersAttachmentsInline imagesIdempotency
yesyesyesyesyesyesmultipleyesyesyesno

These fail with UnsupportedFeatureError and acceptance: "notSubmitted" before any request:

  • An idempotencyKey (feature idempotency).

Idempotency

Not supported. A key fails with UnsupportedFeatureError before sending.

Provider notes

  • Set messageStream to send through a stream other than the server's default. It is sent as MessageStream on every message, so it also applies to layerClient through options.
  • A Postmark ErrorCode other than 0 in a successful response fails the send with acceptance: "rejected".

Using your own client

layerClient takes any object with sendEmail(message), which a ServerClient has. options is optional and accepts timeout and messageStream.

Example (Borrowing a Postmark Client)

import { ServerClient } from "postmark";
import * as Postmark from "@effect-kit/emails/postmark";

const client = new ServerClient("fake-server-token");

const EmailLive = Postmark.layerClient(client, { messageStream: "outbound" });

You own a borrowed client. The Layer never closes it, and the client keeps its own retry, timeout and logging policy.

Errors

ProviderConfigurationError carries provider: "postmark" and a field naming the bad option. Layer construction fails with it, and layerClient fails with it for the client options.

fieldRaised when
timeoutThe timeout is not finite and positive.
tokenThe server token is not printable ASCII without spaces.
messageStreamThe stream id has characters outside letters, digits, underscores and hyphens.
Postmark failureReason
InactiveRecipientsErrorMessageRejectedError
SDK error with status 0 whose name contains TimeoutTimeoutError
SDK error with status 0 otherwiseTransportError

The SDK error's statusCode and code become statusCode and providerCode. Postmark codes kept as providerCode are 0, 10, 401, 406 and 429.

Any other HTTP status uses the shared mapping: 401 is AuthenticationError, 403 PermissionDeniedError, 429 RateLimitedError, 400 and 422 InvalidMessageError, 5xx ProviderUnavailableError, and anything else ProviderError. acceptance is rejected for a 4xx status other than 409 and unknown otherwise. See Errors.