Email Package
@workspace/email
Section titled “@workspace/email”Transactional email system using Resend for delivery and React Email for beautiful, responsive templates.
What’s Included
Section titled “What’s Included”📦 Package Structure
Section titled “📦 Package Structure”packages/email/src/
├── client.ts # Resend client and email functions
├── index.ts # Main exports
└── templates/
├── index.ts # Template exports
└── welcome-email.tsx # Welcome email template
🎯 Core Features
Section titled “🎯 Core Features”- ✅ Resend Integration - Reliable email delivery service
- ✅ React Email Templates - Beautiful, responsive email components
- ✅ Welcome Emails - Automatic sending on user registration
- ✅ Database Tracking -
welcomeMailSent
field tracks delivery - ✅ Type Safety - Full TypeScript support
- ✅ Error Handling - Graceful fallbacks when email service unavailable
📍 Where It’s Used
Section titled “📍 Where It’s Used”apps/api/app/auth/register/route.ts
- Sends welcome emails on registrationpackages/database/src/schema.ts
-welcomeMailSent
field in users tablepackages/email/src/templates/
- React Email components
How It Works
Section titled “How It Works”- User registers → API creates user account
- Welcome email sent →
sendWelcomeEmail()
called with user details - React Email renders → Template converted to HTML
- Resend delivers → Email sent via Resend API
- Database updated →
welcomeMailSent
set totrue
1. Resend Configuration
Section titled “1. Resend Configuration”- Get API key from Resend Dashboard
- Add environment variables:
# apps/api/.env.local
RESEND_API_KEY=re_...
FROM_EMAIL=onboarding@resend.dev # or your domain
2. Domain Verification (Production)
Section titled “2. Domain Verification (Production)”For production, verify your domain in Resend:
- Go to Resend Domains
- Add your domain (e.g.,
yourdomain.com
) - Add DNS records (SPF, DKIM)
- Update
FROM_EMAIL
to your domain:
FROM_EMAIL=hello@yourdomain.com
API Reference
Section titled “API Reference”Core Functions
Section titled “Core Functions”sendEmail(options)
Sends any email with a React Email template:
import { sendEmail } from "@workspace/email";
import { MyCustomEmail } from "./templates/my-custom-email";
const result = await sendEmail({
to: "user@example.com",
subject: "Custom Email",
react: MyCustomEmail({ name: "John" }),
});
if (result.success) {
console.log("Email sent:", result.id);
} else {
console.error("Failed:", result.error);
}
sendWelcomeEmail(email, name)
Sends welcome email to new users:
import { sendWelcomeEmail } from "@workspace/email";
const result = await sendWelcomeEmail("user@example.com", "John Doe");
Email Options
Section titled “Email Options”interface SendEmailOptions {
to: string; // Recipient email
subject: string; // Email subject
react: React.ReactElement; // React Email component
}
Response Format
Section titled “Response Format”// Success
{
success: true;
id: "re_1234567890"; // Resend email ID
}
// Error
{
success: false;
error: "Email service not configured";
}
Creating Templates
Section titled “Creating Templates”React Email Components
Section titled “React Email Components”Create new templates in packages/email/src/templates/
:
// packages/email/src/templates/password-reset.tsx
import {
Body,
Container,
Head,
Heading,
Html,
Preview,
Section,
Text,
Button,
} from "@react-email/components";
import type { FC } from "react";
interface PasswordResetEmailProps {
resetUrl: string;
name: string;
}
export const PasswordResetEmail: FC<PasswordResetEmailProps> = ({
resetUrl,
name,
}) => (
<Html>
<Head />
<Preview>Reset your password, {name}</Preview>
<Body style={main}>
<Container style={container}>
<Section style={box}>
<Heading style={h1}>Reset your password</Heading>
<Text style={text}>
Hi {name}, you requested a password reset.
</Text>
<Button style={button} href={resetUrl}>
Reset Password
</Button>
<Text style={text}>
If you didn't request this, please ignore this email.
</Text>
</Section>
</Container>
</Body>
</Html>
);
const main = {
backgroundColor: "#f6f9fc",
fontFamily:
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
};
const container = {
backgroundColor: "#ffffff",
margin: "0 auto",
padding: "20px 0 48px",
marginBottom: "64px",
};
const box = {
padding: "24px",
borderRadius: "0 0 8px 8px",
textAlign: "center" as const,
};
const h1 = {
color: "#1d2d3d",
fontSize: "24px",
fontWeight: "bold",
margin: "0 0 20px 0",
};
const text = {
color: "#525f7f",
fontSize: "16px",
lineHeight: "24px",
margin: "0 0 10px 0",
};
const button = {
backgroundColor: "#556cd6",
borderRadius: "3px",
color: "#fff",
fontSize: "16px",
textDecoration: "none",
textAlign: "center" as const,
display: "block",
padding: "12px 20px",
margin: "20px 0",
};
Export Template
Section titled “Export Template”// packages/email/src/templates/index.ts
export { WelcomeEmail } from "./welcome-email";
export { PasswordResetEmail } from "./password-reset";
Add Email Function
Section titled “Add Email Function”// packages/email/src/client.ts
import { PasswordResetEmail } from "./templates/password-reset";
export async function sendPasswordResetEmail(
email: string,
name: string,
resetUrl: string
) {
return sendEmail({
to: email,
subject: "Reset your password",
react: PasswordResetEmail({ resetUrl, name }),
});
}
Usage Examples
Section titled “Usage Examples”In API Routes
Section titled “In API Routes”// apps/api/app/auth/reset-password/route.ts
import { sendPasswordResetEmail } from "@workspace/email";
export async function POST(request: Request) {
const { email } = await request.json();
// Generate reset URL
const resetUrl = `${process.env.NEXT_PUBLIC_APP_URL}/reset-password?token=${token}`;
// Send email
const result = await sendPasswordResetEmail(email, user.name, resetUrl);
if (result.success) {
return NextResponse.json({ message: "Reset email sent" });
} else {
return NextResponse.json(
{ error: "Failed to send email" },
{ status: 500 }
);
}
}
In Background Jobs
Section titled “In Background Jobs”// packages/jobs/trigger/send-newsletter.ts
import { task } from "@trigger.dev/sdk/v3";
import { sendEmail } from "@workspace/email";
import { NewsletterEmail } from "./templates/newsletter";
export const sendNewsletter = task({
id: "send-newsletter",
run: async (payload: { subscribers: string[]; content: string }) => {
const results = [];
for (const email of payload.subscribers) {
const result = await sendEmail({
to: email,
subject: "Weekly Newsletter",
react: NewsletterEmail({ content: payload.content }),
});
results.push({ email, success: result.success });
}
return { sent: results.filter((r) => r.success).length };
},
});
Testing
Section titled “Testing”Development
Section titled “Development”# Set up Resend test key
RESEND_API_KEY=re_test_...
FROM_EMAIL=onboarding@resend.dev
# Test email sending
pnpm dev
# Register a new user
# Check email delivery in Resend dashboard
Production
Section titled “Production”# Use production Resend key
RESEND_API_KEY=re_...
FROM_EMAIL=hello@yourdomain.com
# Verify domain in Resend dashboard
# Test with real email addresses
Error Handling
Section titled “Error Handling”The email package gracefully handles errors:
// When RESEND_API_KEY is not set
const result = await sendWelcomeEmail("user@example.com", "John");
// Returns: { success: false, error: "Email service not configured" }
// When Resend API fails
const result = await sendWelcomeEmail("invalid-email", "John");
// Returns: { success: false, error: "Failed to send email" }
Pricing
Section titled “Pricing”- Free tier: 3,000 emails/month
- Pro: $20/month for 50,000 emails
- Enterprise: Custom pricing
See Resend Pricing for details.
Best Practices
Section titled “Best Practices”✅ Template Design
Section titled “✅ Template Design”- Use React Email components for consistency
- Test templates in multiple email clients
- Keep subject lines under 50 characters
- Include both HTML and text versions
✅ Error Handling
Section titled “✅ Error Handling”// Always check result
const result = await sendWelcomeEmail(email, name);
if (!result.success) {
logger.warn("Email failed", { error: result.error, email });
// Continue with user registration even if email fails
}
✅ Performance
Section titled “✅ Performance”- Send emails asynchronously when possible
- Use background jobs for bulk emails
- Cache template rendering for repeated sends
Package Exports
Section titled “Package Exports”// Main functions
import { sendEmail, sendWelcomeEmail } from "@workspace/email";
// Templates
import { WelcomeEmail } from "@workspace/email/templates";