@geenius/emails
v0.17.0
Published
Geenius Emails - transactional and marketing email primitives, provider adapters, framework surfaces, and Convex helpers
Maintainers
Readme
@geenius/emails
Transactional email templates, provider adapters, UI surfaces, and email store helpers for the Geenius ecosystem.
Repository: https://github.com/geenius-dev/geenius-emails
Installation
pnpm add @geenius/emailsSubpath Imports
import { configureEmails, TEMPLATES } from '@geenius/emails'
import { STATUS_CONFIG } from '@geenius/emails'
import { ResendProvider } from '@geenius/emails/providers'
import { EmailDashboardPage } from '@geenius/emails/react'
import {
BatchProgress,
EmailLogTable,
EmailTemplatesPage as ReactCssTemplatesPage,
useEmailSender,
} from '@geenius/emails/react-css'
import '@geenius/emails/react-css/styles.css'
import { EmailDashboardPage as NativeEmailDashboardPage } from '@geenius/emails/react-native'
import { createEmails } from '@geenius/emails/solidjs'
import { EmailDashboardPage as SolidCssDashboardPage } from '@geenius/emails/solidjs-css'
import '@geenius/emails/solidjs-css/styles.css'
import { schema, mutations, queries } from '@geenius/emails/convex'
import { createMemoryEmailsStore } from '@geenius/emails/memory'
import { createCloudflareKVEmailsStore, createMemoryKVNamespace } from '@geenius/emails/cloudflareKV'
import { createNeonEmailsStore } from '@geenius/emails/neon'Usage
import type { EmailTemplate } from '@geenius/emails'
import { TemplateGallery } from '@geenius/emails/react'
const templates: EmailTemplate[] = [
{
id: 'welcome',
name: 'Welcome',
subject: 'Welcome to {{appName}}',
description: 'Sent after signup to orient a new user.',
category: 'auth',
variables: ['appName', 'userName'],
},
]
export function TemplateBrowser() {
return <TemplateGallery templates={templates} />
}React CSS usage
The React CSS subpath exposes the same hooks, components, and page surfaces as
the React variant while shipping static BEM styles from
@geenius/emails/react-css/styles.css.
import type { BatchEmailJob, EmailMessage, EmailTemplateData } from '@geenius/emails'
import {
BatchProgress,
EmailLogTable,
EmailTemplatesPage,
useEmailSender,
} from '@geenius/emails/react-css'
import '@geenius/emails/react-css/styles.css'
const previewData: EmailTemplateData = {
appName: 'Geenius',
dashboardUrl: 'https://app.example.com',
userName: 'Alex',
}
export function EmailOperations(props: {
batches: BatchEmailJob[]
logs: EmailMessage[]
sendEmail: Parameters<typeof useEmailSender>[0]
}) {
const sender = useEmailSender(props.sendEmail)
return (
<>
<EmailLogTable logs={props.logs} />
{props.batches.map(batch => <BatchProgress key={batch.id} batch={batch} />)}
<EmailTemplatesPage previewData={previewData} onSend={templateId => {
void sender.send(templateId, '[email protected]', previewData)
}} />
</>
)
}Variant Guide
@geenius/emails: shared contracts, types, constants, and helpers@geenius/emails/providers: provider implementations for Resend, SES, SMTP, Postmark, SendGrid, and Plunk@geenius/emails/convex: schema, queries, mutations, and Convex component wiring@geenius/emails/convex/convex.config.js: Convex component configuration entrypoint@geenius/emails/neon: Postgres/Neon store factory and idempotent SQL migrations@geenius/emails/cloudflareKV: edge KV store factory and in-memory KV test namespace@geenius/emails/memory: deterministic in-process store for tests, demos, and previews@geenius/emails/react: React hooks, components, and page surfaces@geenius/emails/react-css: React hooks, components, and pages styled with vanilla CSS@geenius/emails/react-native: React Native hooks, components, and page surfaces using native primitives@geenius/emails/solidjs: SolidJS primitives, components, and page surfaces@geenius/emails/solidjs-css: standalone SolidJS components and pages styled with vanilla CSS
This run ships the five public UI variants above plus the four DB providers above. Library variants such as react-mui, react-ant, and solidjs-kobalte are deferred and are intentionally absent from the export map until a later scope includes them. Shared framework-agnostic APIs are imported from @geenius/emails; there is no public @geenius/emails/shared subpath.
Store helpers
import { createMemoryEmailsStore } from '@geenius/emails/memory'
import { createMemoryKVNamespace, createCloudflareKVEmailsStore } from '@geenius/emails/cloudflareKV'
import { createNeonEmailsStore, runEmailsMigrations } from '@geenius/emails/neon'
const memory = createMemoryEmailsStore()
await memory.logEmail({
to: '[email protected]',
subject: 'Welcome',
templateId: 'welcome',
})
const namespace = createMemoryKVNamespace()
const kv = createCloudflareKVEmailsStore({ namespace })
const neon = createNeonEmailsStore({
execute: async (sql, parameters) => {
await db.query(sql, parameters)
},
})
await runEmailsMigrations(async (sql, parameters) => {
await db.query(sql, parameters)
})Storybook
Each in-scope UI variant has a stock Storybook v10 review app:
pnpm storybook:react
pnpm storybook:react-css
pnpm storybook:react-native
pnpm storybook:solidjs
pnpm storybook:solidjs-css- React parity app: apps/storybook-react
- React CSS parity app: apps/storybook-react-css
- React Native parity app: apps/storybook-react-native
- SolidJS parity app: apps/storybook-solidjs
- SolidJS CSS parity app: apps/storybook-solidjs-css
Production builds for the review apps:
pnpm test:storybook:build
pnpm test:storybookContributing tests
Use variants.json as the only source of truth for package variants. Add a new variant there first, then add the matching packages/<variant>/ source, export map entry, Storybook app, e2e harness route, and coverage/bundle budgets.
Core checks:
pnpm lint
pnpm type-check
pnpm test:conventions
pnpm test
pnpm test:coverage
pnpm test:db:conformance
pnpm test:db:migrations
pnpm test:storybookGauntlet scripts:
pnpm test:gauntletruns PR-blocking lint, publish lint, types, unit/root tests, size, supply-chain, and license checks.pnpm test:alladds Storybook, DB conformance, e2e, a11y, visual, perf, and coverage gates.pnpm test:visual --update-snapshotsupdates Playwright visual baselines once the harness is intentionally changed.pnpm test:mutationruns the slower Stryker mutation suite for shared pure logic.
License
FSL-1.1-Apache-2.0
