Skip to content

Mail

@veloxts/mail provides email sending with type-safe React Email templates, supporting SMTP and Resend.

Terminal window
pnpm add @veloxts/mail
# For Resend (recommended)
pnpm add resend
import { mailPlugin } from '@veloxts/mail';
// Log driver - prints to console
app.register(mailPlugin({
driver: 'log',
from: { name: 'My App', email: 'noreply@myapp.com' },
}));
import { defineMail } from '@veloxts/mail';
import { z } from 'zod';
import { Html, Body, Text, Button } from '@react-email/components';
export const WelcomeEmail = defineMail({
name: 'welcome',
schema: z.object({
name: z.string(),
activationUrl: z.string().url(),
}),
subject: ({ name }) => `Welcome, ${name}!`,
template: ({ name, activationUrl }) => (
<Html>
<Body>
<Text>Hello {name}!</Text>
<Button href={activationUrl}>Activate Account</Button>
</Body>
</Html>
),
});
// Basic send
await ctx.mail.send(WelcomeEmail, {
to: 'user@example.com',
data: { name: 'Alice', activationUrl: 'https://...' },
});
// With CC/BCC
await ctx.mail.send(WelcomeEmail, {
to: 'user@example.com',
cc: ['manager@example.com'],
bcc: ['archive@example.com'],
data: { ... },
});
// With attachments
await ctx.mail.send(InvoiceEmail, {
to: 'user@example.com',
data: { invoice },
attachments: [
{ filename: 'invoice.pdf', content: pdfBuffer },
],
});

Log

Console output for development and testing.

Resend

Modern API with React Email integration.

SMTP

Traditional SMTP for any provider.

ProviderBest For
ResendSimple API, React Email native
AWS SESHigh volume, cost-effective
SendGridEnterprise features
PostmarkTransactional focus
.env (Resend)
RESEND_API_KEY=re_xxxxxxxxxxxx
.env (SMTP)
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-username
SMTP_PASS=your-password
  1. Verify sending domain - SPF, DKIM, DMARC
  2. Use environment variables - Never hardcode credentials
  3. Verified From address - Use domain email
  4. Handle bounces - Webhook for bounce/complaints
  5. Queue emails - Use @veloxts/queue for background sending

Don’t block requests with email sending:

const sendEmailJob = defineJob({
name: 'email.send',
schema: z.object({
template: z.string(),
to: z.string().email(),
data: z.record(z.unknown()),
}),
handler: async ({ data, ctx }) => {
const template = templates[data.template];
await ctx.mail.send(template, { to: data.to, data: data.data });
},
});
// Dispatch instead of sending directly
await ctx.queue.dispatch(sendEmailJob, {
template: 'welcome',
to: 'user@example.com',
data: { name: 'Alice', activationUrl: '...' },
});