Prisma
Send transactional email after Prisma writes with Samva.
Prisma
Use Prisma for persistence and the samva SDK for transactional email. The
primary pattern is query-then-send: create or update the row, then send email
from the persisted data.
Samva sends from the verified sender configured on your account, so there is
no from field in the send payload.
Install
bun add samva @prisma/clientKeep SAMVA_API_KEY server-side only:
import "server-only";
import { createClient } from "samva";
const apiKey = process.env.SAMVA_API_KEY;
if (!apiKey) {
throw new Error("SAMVA_API_KEY is required");
}
export const samva = createClient({ apiKey });Query, then send
Use the committed row as the source of truth for the email:
import { prisma } from "@/lib/prisma";
import { samva } from "@/lib/samva";
const order = await prisma.order.create({
data: {
email: "ada@example.com",
total: 4900,
status: "confirmed",
},
});
await samva.messages.send({
to: [{ email: order.email }],
channel: "email",
email: {
subject: `Order #${order.id} confirmed`,
html: `<p>Thanks. Your order total is ${order.total}.</p>`,
},
});This keeps the boundary clear: Prisma owns database state, Samva owns delivery. If you need durable retries, write an outbox row in the same database transaction and let a worker send from that outbox after commit.
Data-layer hook
For advanced cases, Prisma Client Extensions can centralize the send around a specific write:
import { PrismaClient } from "@prisma/client";
import { samva } from "@/lib/samva";
const base = new PrismaClient();
const prisma = base.$extends({
name: "samva-order-emails",
query: {
order: {
async create({ args, query }) {
const order = await query(args);
await samva.messages.send({
to: [{ email: order.email }],
channel: "email",
email: {
subject: `Order #${order.id} confirmed`,
html: `<p>Thanks. Your order total is ${order.total}.</p>`,
},
});
return order;
},
},
},
});Use this only when the data layer really owns the side effect. For transaction correctness, send after an interactive transaction resolves or use an outbox; email delivery cannot be rolled back with the database write.
Runtime notes
The Samva SDK is fetch-based, so the send works in Node, Workers, and edge
runtimes. Prisma can query at the edge when you use the Rust-free client with an
edge-compatible driver adapter.
React Email works well for templates: render the component to html, derive a
plain-text fallback, and pass both strings to Samva. See the
React Email integration for the template
workflow.
Signup, reset, magic link, and OTP emails should live in your auth callbacks instead of a generic Prisma write hook. See the Better Auth integration for that callback shape.
Full cookbook
The cookbook link resolves after the companion samva-integrations PR lands.