Message transformations
Prepare trusted replacement content without changing operation keys, policy or approved intent.
Use root transformedEmailLayer to run application-owned message preparation around an Email Layer:
import { DateTime, Effect, Redacted } from "effect";
import { Email, transformedEmailLayer } from "@corven/email-sdk";
import { defaultedEmailLayer } from "@corven/email-sdk/defaults";
import { resendEmailLayer } from "@corven/email-sdk/resend";
const account = transformedEmailLayer(
defaultedEmailLayer(resendEmailLayer({ apiKey: Redacted.make("fictional-unused-key") }), {
idempotencyKeyPrefix: "fictional-notifications/",
replyTo: "replies@fictional.invalid",
}),
({ message, options }) =>
Effect.succeed({
...message,
subject:
options.executionMetadata?.priority === "urgent"
? `[Action requested] ${message.subject}`
: message.subject,
}),
);
export const fictionalTransformedSubmission = Effect.gen(function* prepareNotification() {
const email = yield* Email;
const operation = yield* email.prepare(
{
body: { text: "A fictional transformation example." },
from: "sender@fictional.invalid",
subject: "Fictional notification",
to: "recipient@fictional.invalid",
},
{
executionMetadata: {
audit: {
at: DateTime.makeUnsafe("2026-01-02T03:04:05.123Z"),
flags: [0, false, null, undefined],
},
priority: "urgent",
},
idempotencyKey: "caller-owned-logical-event",
},
);
return { preview: operation.previews[0], receipt: yield* operation.send };
}).pipe(Effect.provide(account));
export const fictionalContextualAudience = Effect.gen(function* prepareContextualAudience() {
const email = yield* Email;
return yield* email.sendPersonalized(
{
message: {
body: { text: "Hello %recipient.name%. Your notification is ready." },
from: "sender@fictional.invalid",
subject: "Fictional notification for %recipient.name%",
},
recipients: [
{ to: "first@fictional.invalid", variables: { name: "First" } },
{ to: "second@fictional.invalid", variables: { name: "Second" } },
],
},
{ executionMetadata: { priority: "urgent" } },
);
}).pipe(Effect.provide(account));
The transform receives owned message/options and returns replacement message input as an Effect. The example uses private execution context to choose a subject prefix; that context is not automatically forwarded to the provider.
Preserve operation authority
A transform replaces message data, not operation keys or delivery policy. It cannot dispatch after local refusal or convert an observation failure into permission to resend. Its returned message still passes common decoding and provider validation.
Supply a closed callback, or an acquisition Effect that captures its dependencies within the Layer through EmailExtension. Resources acquired there last for the owning Layer scope; a returned prepared operation does not extend that lifetime.
Review once
Prepare the message after defaults and transformations, review the actual candidates, and send that same prepared operation. Recomputing a transformation after approval can create content that was never approved.
This wrapper requires Individual personalization and rejects native audiences. For a provider-managed template, use the native job service rather than a transformation that silently changes the sending model.