@vetaui/email-kit
v0.1.2
Published
Veta email kit — provider-agnostic transactional email (Resend / SendGrid / AWS SES / mock) + UI for templates, logs, unsubscribe pages.
Maintainers
Readme
@vetaui/email-kit
Provider-agnostic transactional email for Next.js + drop-in UI for templates, logs, and unsubscribe pages. Pick a backend, configure once, every screen + every server action calls the same sendEmail().
Install
pnpm add @vetaui/email-kit @vetaui/foundations @vetaui/atoms @vetaui/molecules
# + the SDK for whichever provider you choose:
pnpm add resend # Resend
pnpm add @sendgrid/mail # SendGrid
pnpm add @aws-sdk/client-ses # AWS SESConfigure once
// app/veta.config.ts
import { configureVeta } from "@vetaui/foundations/runtime";
import { resendEmailStrategy } from "@vetaui/email-kit/strategies";
configureVeta({
email: resendEmailStrategy({
apiKey: process.env.RESEND_KEY!,
defaultFrom: "[email protected]",
}),
});Use anywhere
// app/api/contact/route.ts
import { sendEmail } from "@vetaui/email-kit";
export async function POST(req: Request) {
const { email, message } = await req.json();
await sendEmail({
from: "[email protected]",
to: ["[email protected]"],
subject: "New contact",
text: `${email}: ${message}`,
tag: "contact-form",
});
return Response.json({ ok: true });
}Drop-in screens
import { TemplateLibraryPage, EmailLogPage, UnsubscribePage } from "@vetaui/email-kit/screens";
import { listEmailLogs } from "@vetaui/email-kit";
export default async function Page() {
const entries = await listEmailLogs({ limit: 100 });
return <EmailLogPage entries={entries} onSelect={(e) => router.push(`/admin/email/${e.id}`)} />;
}Adapters
| Adapter | Capabilities | Edge runtime? |
|---|---|---|
| resendEmailStrategy | transactional + marketing + 1-click unsubscribe | ✓ |
| sendgridEmailStrategy | transactional + marketing + categories | ✓ |
| awsSesEmailStrategy | transactional only | ✗ (Node only) |
| mockEmailStrategy | everything (in-memory) | ✓ |
Custom adapter? Implement EmailStrategy from @vetaui/email-kit/strategies — 1 method (send) is required, the rest are optional and screens degrade automatically via getCapabilities().
