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

Plunk

Send email through Plunk with the @effect-kit/emails/plunk Layer.

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

Installation

npm install @effect-kit/emails effect @plunk/node@3.0.3

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

Setup

Plunk.layerConfig() reads these variables:

VariableRequiredValue
PLUNK_API_KEYyesSecret API key, starting with sk_

Example (Sending a Message With Plunk)

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

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

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

.(.(.()));

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

Options

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

Prop

Type

Capabilities

Plunk reports this in email.capabilities:

TextHTMLBothSender nameCcBccReply-toHeadersAttachmentsInline imagesIdempotency
noyesnoyesnonononenononono

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

  • A text body (feature text).
  • A cc list (feature cc).
  • A bcc list (feature bcc).
  • Any replyTo address (feature replyTo).
  • Any custom header (feature headers).
  • Any attachment (feature attachments).
  • An idempotencyKey (feature idempotency).

Idempotency

Not supported. A key fails with UnsupportedFeatureError before sending.

Provider notes

  • Plunk is HTML only. A message needs html and exactly one to address without a name. A text-only message fails the capability check, and a message without html or with a named or second recipient fails with InvalidMessageError (path to).
  • Only from, the sender name, to, subject and the HTML body are sent. Anything else fails the capability check first: text, cc, bcc, replyTo, headers and attachments.
  • The @plunk/node package is marked as no longer supported on npm. Pin it to the version above.
  • A send is accepted when Plunk reports the recipient as queued. The status throttled or skipped fails with MessageRejectedError. The receipt's single reference is the recipient address.

Using your own client

layerClient takes any object with emails.send({ to, from, name, subject, body }), which a Plunk client has. options is optional.

Example (Borrowing a Plunk Client)

import Plunk from "@plunk/node";
import * as PlunkEmail from "@effect-kit/emails/plunk";

const client = new Plunk("sk_fake_key");

const EmailLive = PlunkEmail.layerClient(client);

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: "plunk" 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 key is not printable ASCII without spaces.
apiKeyThe key does not start with sk_.
baseUrlThe URL is not http or https, has credentials, a query or a fragment, or its path does not end with a slash.
Plunk failureReason
SDK token errorAuthenticationError (status 401, acceptance: "rejected")
SDK not found errorProviderError (status 404)
A plain Error from the SDKProviderError
Recipient status throttled or skippedMessageRejectedError (acceptance: "rejected")
Any other status except queuedUnexpectedResponseError

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. A network failure with no status is TransportError, and ETIMEDOUT or ECONNABORTED is TimeoutError, both with acceptance: "unknown".