@lastshotlabs/slingshot-mail
npm install @lastshotlabs/slingshot-mail
Functions
Section titled “Functions”createBullMQMailQueue
Section titled “createBullMQMailQueue”Creates a durable, Redis-backed mail queue powered by BullMQ.
Requires bullmq and ioredis as installed dependencies — both are optional peers.
The queue tests the Redis connection eagerly on start() to surface misconfiguration
at startup rather than at first delivery attempt.
Non-retryable failures (e.g. provider-rejected messages) are wrapped in
BullMQ.UnrecoverableError so they bypass BullMQ’s built-in retry backoff and are
dead-lettered immediately. The original MailSendError context (statusCode,
providerError) is preserved and forwarded to onDeadLetter.
function createBullMQMailQueue(config: BullMQMailQueueConfig): MailQueueSource: packages/slingshot-mail/src/queues/bullmq.ts
createMailPlugin
Section titled “createMailPlugin”Creates the slingshot-mail plugin for event-driven transactional email delivery.
Validates the config and adapter shapes at construction time (fail-fast). Mail delivery
is entirely event-driven — subscribe to SlingshotEventMap keys via config.subscriptions
and the plugin dispatches templated emails automatically when those events fire.
function createMailPlugin(rawConfig: MailPluginConfig): SlingshotPluginSource: packages/slingshot-mail/src/plugin.ts
createMemoryQueue
Section titled “createMemoryQueue”Creates an in-process, non-durable mail queue for development and testing.
Jobs are held in memory and processed inline - no external dependencies required.
This queue is not suitable for production: all pending jobs are lost on process
restart. Use createBullMQMailQueue for durable, Redis-backed delivery.
Remarks: Prints a startup warning to console.warn to make the non-durable nature visible. The warning is intentional and should not be suppressed.
function createMemoryQueue(config?: MailQueueConfig): MailQueueSource: packages/slingshot-mail/src/queues/memory.ts
createPostmarkProvider
Section titled “createPostmarkProvider”Creates a MailProvider backed by the Postmark API.
Uses the POST /email endpoint directly via fetch — no SDK dependency required.
Rate-limit (429) and server errors (5xx) are marked retryable; all other failures are
treated as permanent.
function createPostmarkProvider(config: PostmarkConfig): MailProviderSource: packages/slingshot-mail/src/providers/postmark.ts
createRawHtmlRenderer
Section titled “createRawHtmlRenderer”Creates a MailRenderer that interpolates simple {{variable}} placeholders into
static HTML string templates.
No templating engine or build step required - templates are plain strings defined inline
in code. For rich component-based templates, use createReactEmailRenderer instead.
function createRawHtmlRenderer(config: RawHtmlRendererConfig): MailRendererSource: packages/slingshot-mail/src/renderers/rawHtml.ts
createReactEmailRenderer
Section titled “createReactEmailRenderer”Creates a MailRenderer backed by @react-email/render.
Components are plain React functional components that receive the dataMapper output as
props. @react-email/render is loaded lazily on first render - install it as a peer
dependency. Plain-text extraction is attempted via render(..., { plainText: true });
if it fails the text body is omitted with a warning.
Remarks: Components must be synchronous. Async server components are not supported by @react-email/render.
function createReactEmailRenderer(config: ReactEmailRendererConfig): MailRendererSource: packages/slingshot-mail/src/renderers/reactEmail.ts
createResendProvider
Section titled “createResendProvider”Creates a MailProvider backed by the Resend API.
Uses the POST /emails endpoint directly via fetch — no SDK dependency required.
Rate-limit (429) and server errors (5xx) are marked retryable; all other failures are
treated as permanent.
function createResendProvider(config: ResendConfig): MailProviderSource: packages/slingshot-mail/src/providers/resend.ts
createSendgridProvider
Section titled “createSendgridProvider”Creates a MailProvider backed by the SendGrid Mail Send API v3.
Uses the POST /v3/mail/send endpoint directly via fetch — no SDK dependency required.
SendGrid returns HTTP 202 Accepted for queued messages, so SendResult.status is always
'sent' (delivery is async on SendGrid’s end). Rate-limit (429) and server errors (5xx)
are marked retryable.
function createSendgridProvider(config: SendgridConfig): MailProviderSource: packages/slingshot-mail/src/providers/sendgrid.ts
createSesProvider
Section titled “createSesProvider”Creates a MailProvider backed by AWS SES v2 (@aws-sdk/client-sesv2).
The AWS SDK is loaded lazily on first send — install @aws-sdk/client-sesv2 as a peer
dependency. Credentials can be provided explicitly or resolved from the environment
(IAM roles, ~/.aws/credentials, etc.).
function createSesProvider(config: SesConfig): MailProviderSource: packages/slingshot-mail/src/providers/ses.ts
mailPluginConfigSchema
Section titled “mailPluginConfigSchema”Zod schema for validating MailPluginConfig at runtime.
Used internally by createMailPlugin — call validatePluginConfig against this.
Source: packages/slingshot-mail/src/types/config.ts
validateSubscriptionTemplates
Section titled “validateSubscriptionTemplates”Validates that every subscription’s template is known to the configured renderer.
Throws a MailTemplateNotFoundError listing the first missing template so callers
can surface the misconfiguration at startup instead of at first event delivery.
async function validateSubscriptionTemplates(config: MailPluginConfig): Promise<void>Source: packages/slingshot-mail/src/lib/subscriptionWiring.ts
Classes
Section titled “Classes”MailCircuitOpenError
Section titled “MailCircuitOpenError”Thrown when the breaker is open and refuses to invoke the provider.
retryAfterMs is the time remaining until the breaker enters half-open
state. Workers can surface this as a backoff hint instead of treating the
rejection as a generic transient failure.
Source: packages/slingshot-mail/src/lib/circuitBreaker.ts
MailSendError
Section titled “MailSendError”Thrown by MailProvider.send() when delivery fails.
The retryable flag controls queue behaviour: non-retryable errors (e.g. invalid recipient,
API auth failure) are dead-lettered immediately; retryable errors (e.g. rate limit, 5xx) are
re-enqueued up to config.queueConfig.maxAttempts.
Source: packages/slingshot-mail/src/types/provider.ts
MailTemplateNotFoundError
Section titled “MailTemplateNotFoundError”Thrown at plugin startup when a subscription’s template cannot be found in the configured renderer. Lets callers fail fast instead of waiting for the first matching event to fire at runtime.
Source: packages/slingshot-mail/src/lib/subscriptionWiring.ts
Interfaces
Section titled “Interfaces”MailCircuitBreaker
Section titled “MailCircuitBreaker”Runtime circuit breaker guarding outbound mail provider calls.
Source: packages/slingshot-mail/src/lib/circuitBreaker.ts
MailCircuitBreakerHealth
Section titled “MailCircuitBreakerHealth”Snapshot of breaker state — useful for health endpoints and metrics.
Source: packages/slingshot-mail/src/lib/circuitBreaker.ts
MailCircuitBreakerOptions
Section titled “MailCircuitBreakerOptions”Tunable options used to construct a mail provider circuit breaker.
Source: packages/slingshot-mail/src/lib/circuitBreaker.ts
MailJob
Section titled “MailJob”A single mail delivery job tracked by the queue.
Exposed to onDeadLetter callbacks so callers can inspect what failed and why.
Source: packages/slingshot-mail/src/types/queue.ts
MailMessage
Section titled “MailMessage”A fully-resolved email message ready to be handed to a MailProvider.
The html field is required; providers that support a text fallback will use text
when present. from overrides the plugin-level default when set.
Source: packages/slingshot-mail/src/types/provider.ts
MailProvider
Section titled “MailProvider”Interface that every mail transport adapter must implement.
Implementations are provided for Resend, SES, Postmark, and SendGrid. Implement this interface directly to support a custom transport.
Remarks: send() must throw MailSendError with retryable set correctly so the queue can make an informed retry decision. Non-MailSendError rejections are treated as retryable.
Source: packages/slingshot-mail/src/types/provider.ts
MailQueue
Section titled “MailQueue”Interface that every mail queue implementation must satisfy.
Extend QueueLifecycle (start, stop, depth, drain) with mail-specific
enqueue and start(provider). The in-process MemoryQueue and BullMQ-backed
queue both implement this interface.
Remarks: Implement this interface to integrate a custom queue backend (e.g. SQS, RabbitMQ).
Source: packages/slingshot-mail/src/types/queue.ts
MailQueueConfig
Section titled “MailQueueConfig”Configuration shared by all queue implementations.
Used when config.queue is omitted from MailPluginConfig so the plugin can create a
default MemoryQueue; also accepted directly by createBullMQMailQueue.
Source: packages/slingshot-mail/src/types/queue.ts
MailSubscription
Section titled “MailSubscription”Declarative binding from a bus event to a mail template.
When the bus emits event, the plugin resolves the recipient via recipientMapper,
renders template with data from dataMapper, and enqueues a delivery.
Source: packages/slingshot-mail/src/types/config.ts
RawHtmlTemplate
Section titled “RawHtmlTemplate”A static HTML template with optional {{variable}} interpolation placeholders.
Variable syntax: {{key}} - all values are coerced to strings safely.
Missing keys render as empty strings rather than throwing.
Source: packages/slingshot-mail/src/renderers/rawHtml.ts
SendResult
Section titled “SendResult”The result returned by a MailProvider after attempting to send a message.
sent— provider accepted and transmitted the message.queued_by_provider— provider accepted and will deliver asynchronously (e.g. SendGrid).rejected— provider accepted the request but explicitly rejected the message (e.g. hard bounce rules). The message should be dead-lettered, not retried.
Source: packages/slingshot-mail/src/types/provider.ts
MailAddress
Section titled “MailAddress”An email address, expressed either as a bare address string or a structured object.
Source: packages/slingshot-mail/src/types/provider.ts
MailPluginConfig
Section titled “MailPluginConfig”Configuration object accepted by createMailPlugin.
Inferred from mailPluginConfigSchema — use the schema for runtime validation.
Source: packages/slingshot-mail/src/types/config.ts