Skip to content

Email And Notifications

Use @bnomei/emdash-mika/email for built-in email rendering helpers.

Mika ships default rows and renderers for magic links and order confirmations. Other notification kinds are hook-only until default renderers are intentionally added.

Trusted backends can pass a notification hook to createMikaBackendApi(). Returning { handled: true } suppresses Mika’s default email for the intent when one exists.

Notification flow:

Stage Owner
Operation emits MikaNotificationIntent Mika backend
Optional host hook handles or declines the intent Host app
Built-in renderer creates default email when one exists Mika
Outbox runner leases and sends queued rows Mika runner plus host sender
Transport, sender identity, retries outside the outbox, and deliverability Host app
File or subpath Role
@bnomei/emdash-mika/email Pure rendering helpers for built-in transactional templates.
@bnomei/emdash-mika/server Exports notification hook types, email outbox runner helpers, and the backend API constructor.
src/api/notifications.ts Defines notification intent kinds and emitMikaNotification().
src/api/email-outbox.ts Leases queued email documents, renders built-in templates, calls the host sender, and records retry state.
src/api/maintenance.ts Runs the optional email outbox task when an emailOutboxRunner is configured.

Mika does not include an SMTP, SES, Postmark, Resend, or EmDash account configuration. The host owns the actual transport and sender identity.

Built-in renderer exports:

  • mikaEmailTemplates;
  • renderMikaMagicLinkEmail();
  • renderMikaOrderConfirmationEmail();
  • renderMikaEmail(template, input);
  • MikaEmailBrand;
  • MikaRenderedEmail;
  • MikaMagicLinkEmailInput;
  • MikaOrderConfirmationEmailInput.

renderMikaEmail() dispatches by template key. Built-in template keys are magic_link and order_confirmation.

Pass a hook to createMikaBackendApi({ notifications: { handle } }). The hook receives an intent and returns { handled: true } to suppress Mika’s default email for that kind:

import { renderMikaMagicLinkEmail } from "@bnomei/emdash-mika/email";
const notifications = {
handle: async (intent) => {
if (intent.kind === "magic_link.requested") {
const email = renderMikaMagicLinkEmail({
toEmail: intent.context.toEmail,
url: intent.context.link,
purpose: intent.context.purpose,
expiresAt: intent.context.expiresAt,
});
await deliver(email); // host-owned transport
return { handled: true };
}
return { handled: false };
},
};

Notification kinds include magic_link.requested, order.confirmed, checkout.payment_failed, download.ready, license.issued, subscription.started / updated / renewal_failed, account.export_ready, account.delete_requested, and ops.webhook_failed. Default renderers ship only for magic_link.requested and order.confirmed (renderMikaMagicLinkEmail, renderMikaOrderConfirmationEmail, or the generic renderMikaEmail); the rest are hook-only until you render and deliver them.

emitMikaNotification() first calls the host hook. If the hook is missing or does not return { handled: true }, the backend runs the default handler for that intent when one exists. The default handlers enqueue outbox records for magic links and order confirmations.

Use createMikaEmailOutboxRunner() from @bnomei/emdash-mika/server when the host wants Mika to drain queued email documents:

import {
createEmDashMikaEmailSender,
createMikaEmailOutboxRunner,
} from "@bnomei/emdash-mika/server";
const emailOutboxRunner = createMikaEmailOutboxRunner({
repositories,
sender: createEmDashMikaEmailSender(locals.emdash.email),
brand: { siteName: "Acme Shop", supportEmail: "support@example.com" },
});

The runner:

  • reads due emails from the ops repository;
  • leases each email before delivery;
  • renders magic_link or order_confirmation;
  • calls the host MikaEmailSender;
  • marks emails sent, failed, skipped, lease_missed, or lease_lost;
  • computes retry timing with retryDelayMs or default retry behavior.

createEmDashMikaEmailSender() adapts locals.emdash.email into a Mika sender. It expects the EmDash sender to accept a source argument unless allowPluginScopedSender is set.

Maintenance runs the outbox only if the plugin/native entrypoint passes an emailOutboxRunner. Otherwise the email outbox maintenance task is skipped.

Next: Backend And Provider shows the hook in context. Maintenance lists the scheduled outbox task result.

  • ../emdash-mika/src/email.ts
  • ../emdash-mika/src/server.ts
  • ../emdash-mika/src/api/notifications.ts
  • ../emdash-mika/src/api/email-outbox.ts
  • ../emdash-mika/src/api/backend.ts
  • ../emdash-mika/src/api/maintenance.ts