Sending many
Send a list of messages with bounded concurrency and get one result per message.
Email.sendMany sends a list of requests and returns one Result per request, in input order. A message that fails does not stop the others.
Example (Collecting Failures From a Batch)
import { , } from "effect";
import { } from "@effect-kit/emails";
const = .(function* () {
const outcomes = yield* .([ {
: {
: "hello@example.com",
: "ada@example.com",
: "Welcome",
: "Your account is ready.",
},
},
{
: {
: "hello@example.com",
: "grace@example.com",
: "Welcome",
: "Your account is ready.",
},
},
]);
const = .(.);
return .(() => ..);
});Each request is an EmailRequest: a message, plus optional options with an idempotencyKey. Email.sendMany runs against whichever Email is provided, so it works with the test Layer too.
Concurrency
Pass BatchOptions as the second argument. concurrency is an integer from 1 to 1000 and defaults to 5.
Example (Sending Ten at a Time)
import { } from "effect";
import { , type } from "@effect-kit/emails";
declare const : [];
const program = .(, { : 10 });Limits
A batch holds at most 1,000 requests. An empty list is valid and returns an empty array.
Email.sendMany fails with BatchError only when the input is invalid, before any request is made. reason is "InvalidRequests" for a non-array or more than 1,000 requests, and "InvalidOptions" for bad BatchOptions. Per-message errors never reach the error channel: they are failed results.
A message that is invalid becomes a failed result with acceptance: "notSubmitted" and is not submitted.
What a batch is not
A batch is a bounded loop over email.send. It is not atomic, it uses no provider batch API and it does not retry. It never generates idempotency keys: keys you set on a request are passed through.
The results already contain each acceptance, so decide per result whether to retry.