Email Service
Reliable email delivery service using Resend with React Email templates. Send transactional and marketing emails with beautiful, responsive templates.
Installation & Setup
1. Install Dependencies
pnpm add resend react-email @react-email/components2. Configure Environment Variables
# .env
RESEND_API_KEY=re_xxxxxxxxxxxx
EMAIL_FROM=hello@orbitus.dev3. Usage
The Email Service is available as a singleton via getEmailService or can be instantiated manually.
Singleton (Recommended)
import { getEmailService } from '@orbitusdev/core/services/email';
const emailService = getEmailService();Manual Instantiation
For advanced use cases (e.g., custom configuration):
import { EmailService } from '@orbitusdev/core/services/email';
// Provider config is typically handled within the service or passed explicitly
const emailService = new EmailService('resend', {
apiKey: process.env.RESEND_API_KEY
});Email Templates
Welcome Email
// emails/welcome.tsx
import {
Body,
Button,
Container,
Head,
Heading,
Html,
Preview,
Section,
Text
} from '@react-email/components';
interface WelcomeEmailProps {
username: string;
loginUrl: string;
}
export function WelcomeEmail({ username, loginUrl }: WelcomeEmailProps) {
return (
<Html>
<Head />
<Preview>Welcome to Orbitus - Let's get started!</Preview>
<Body style={main}>
<Container style={container}>
<Heading style={h1}>Welcome to Orbitus! 🎉</Heading>
<Text style={text}>Hi {username},</Text>
<Text style={text}>
We're excited to have you on board. Your account has been successfully created.
</Text>
<Section style={buttonContainer}>
<Button style={button} href={loginUrl}>
Get Started
</Button>
</Section>
<Text style={text}>
If you have any questions, feel free to reply to this email.
</Text>
<Text style={footer}>
Best regards,
<br />
The Orbitus Team
</Text>
</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 h1 = {
color: '#333',
fontSize: '24px',
fontWeight: 'bold',
margin: '40px 0',
padding: '0'
};
const text = {
color: '#333',
fontSize: '16px',
lineHeight: '26px'
};
const buttonContainer = {
padding: '27px 0 27px'
};
const button = {
backgroundColor: '#000',
borderRadius: '5px',
color: '#fff',
fontSize: '16px',
fontWeight: 'bold',
textDecoration: 'none',
textAlign: 'center' as const,
display: 'block',
width: '200px',
padding: '14px 7px'
};
const footer = {
color: '#8898aa',
fontSize: '14px',
lineHeight: '16px',
marginTop: '32px'
};Email Verification
// emails/verify-email.tsx
import {
Body,
Button,
Container,
Head,
Heading,
Html,
Preview,
Section,
Text
} from '@react-email/components';
interface VerifyEmailProps {
username: string;
verificationUrl: string;
verificationCode: string;
}
export function VerifyEmail({
username,
verificationUrl,
verificationCode
}: VerifyEmailProps) {
return (
<Html>
<Head />
<Preview>Verify your email address</Preview>
<Body style={main}>
<Container style={container}>
<Heading style={h1}>Verify your email</Heading>
<Text style={text}>Hi {username},</Text>
<Text style={text}>
Please verify your email address by clicking the button below:
</Text>
<Section style={buttonContainer}>
<Button style={button} href={verificationUrl}>
Verify Email
</Button>
</Section>
<Text style={text}>Or use this verification code:</Text>
<Section style={codeContainer}>
<Text style={code}>{verificationCode}</Text>
</Section>
<Text style={text}>
This link will expire in 24 hours. If you didn't request this, please ignore this email.
</Text>
</Container>
</Body>
</Html>
);
}
const codeContainer = {
background: '#f4f4f4',
borderRadius: '4px',
margin: '16px auto 14px',
verticalAlign: 'middle',
width: '280px'
};
const code = {
color: '#000',
display: 'inline-block',
fontFamily: 'monospace',
fontSize: '32px',
fontWeight: 700,
letterSpacing: '6px',
lineHeight: '40px',
paddingBottom: '8px',
paddingTop: '8px',
margin: '0 auto',
width: '100%',
textAlign: 'center' as const
};
// ... (same styles as WelcomeEmail)Password Reset
// emails/reset-password.tsx
import {
Body,
Button,
Container,
Head,
Heading,
Html,
Preview,
Section,
Text
} from '@react-email/components';
interface ResetPasswordProps {
username: string;
resetUrl: string;
}
export function ResetPassword({ username, resetUrl }: ResetPasswordProps) {
return (
<Html>
<Head />
<Preview>Reset your password</Preview>
<Body style={main}>
<Container style={container}>
<Heading style={h1}>Reset your password</Heading>
<Text style={text}>Hi {username},</Text>
<Text style={text}>
We received a request to reset your password. Click the button below to create a new password:
</Text>
<Section style={buttonContainer}>
<Button style={button} href={resetUrl}>
Reset Password
</Button>
</Section>
<Text style={text}>
This link will expire in 1 hour. If you didn't request a password reset, please ignore this email.
</Text>
<Text style={text}>
For security reasons, we cannot reset your password automatically.
</Text>
</Container>
</Body>
</Html>
);
}
// ... (same styles)Usage Examples
Send Welcome Email
import { getEmailService } from '@orbitusdev/core/services/email';
import { WelcomeEmail } from '@/emails/welcome';
export async function sendWelcomeEmail(user: { email: string; name: string }) {
const emailService = getEmailService();
await emailService.sendEmail({
to: user.email,
subject: 'Welcome to Orbitus! 🎉',
html: '', // React templates usually render to HTML, but here we pass react component if supported or render it first
// Note: The current EmailService expects 'html' or 'text'.
// If using React Email, render it to HTML string first:
// html: render(<WelcomeEmail ... />)
// For this example, assuming we render it:
react: WelcomeEmail({
username: user.name,
loginUrl: 'https://orbitus.dev/login'
})
});
}Send Verification Email
import { getEmailService } from '@orbitusdev/core/services/email';
import { VerifyEmail } from '@/emails/verify-email';
export async function sendVerificationEmail(user: {
email: string;
name: string;
verificationToken: string;
}) {
const emailService = getEmailService();
const verificationUrl = `https://orbitus.dev/verify?token=${user.verificationToken}`;
await emailService.sendEmail({
to: user.email,
subject: 'Verify your email address',
react: VerifyEmail({
username: user.name,
verificationUrl,
verificationCode: user.verificationToken.slice(0, 6).toUpperCase()
})
});
}Send Password Reset Email
import { getEmailService } from '@orbitusdev/core/services/email';
import { ResetPassword } from '@/emails/reset-password';
export async function sendPasswordResetEmail(user: {
email: string;
name: string;
resetToken: string;
}) {
const emailService = getEmailService();
const resetUrl = `https://orbitus.dev/reset-password?token=${user.resetToken}`;
await emailService.sendEmail({
to: user.email,
subject: 'Reset your password',
react: ResetPassword({
username: user.name,
resetUrl
})
});
}Server Actions
Complete Auth Flow
'use server';
import { sendWelcomeEmail, sendVerificationEmail } from '@/lib/email';
export async function registerUser(formData: FormData) {
const email = formData.get('email') as string;
const name = formData.get('name') as string;
// Create user
const user = await prisma.user.create({
data: {
email,
name,
verificationToken: generateToken()
}
});
// Send welcome and verification emails
await Promise.all([
sendWelcomeEmail(user),
sendVerificationEmail(user)
]);
return { success: true };
}Newsletter Templates
Newsletter Email
// emails/newsletter.tsx
import {
Body,
Container,
Head,
Heading,
Html,
Img,
Link,
Preview,
Section,
Text
} from '@react-email/components';
interface NewsletterProps {
articles: Array<{
title: string;
excerpt: string;
url: string;
image: string;
}>;
}
export function Newsletter({ articles }: NewsletterProps) {
return (
<Html>
<Head />
<Preview>Latest updates from Orbitus</Preview>
<Body style={main}>
<Container style={container}>
<Heading style={h1}>📰 Latest from Orbitus</Heading>
{articles.map((article) => (
<Section key={article.url} style={articleSection}>
<Img src={article.image} alt={article.title} style={image} />
<Heading style={h2}>{article.title}</Heading>
<Text style={text}>{article.excerpt}</Text>
<Link href={article.url} style={link}>
Read more →
</Link>
</Section>
))}
<Text style={footer}>
You're receiving this because you subscribed to Orbitus newsletter.
<br />
<Link href="https://orbitus.dev/unsubscribe">Unsubscribe</Link>
</Text>
</Container>
</Body>
</Html>
);
}
const articleSection = {
marginBottom: '32px',
paddingBottom: '32px',
borderBottom: '1px solid #e5e5e5'
};
const image = {
width: '100%',
borderRadius: '8px',
marginBottom: '16px'
};
const h2 = {
fontSize: '20px',
lineHeight: '28px',
fontWeight: 'bold',
margin: '16px 0'
};
const link = {
color: '#000',
fontSize: '16px',
fontWeight: 'bold'
};
// ... (same base styles)Best Practices
- Use environment variables - Never hardcode API keys
- Validate email addresses - Check format before sending
- Handle errors gracefully - Log failures, retry if needed
- Use preview text - Shows in email client preview
- Responsive design - Test on mobile and desktop
- Plain text fallback - Include text version
- Unsubscribe links - Required for marketing emails
- Rate limiting - Prevent spam, respect Resend limits
- Test templates - Use React Email preview mode
- Track deliverability - Monitor bounce and spam rates
Testing
Preview Emails Locally
# Start React Email dev server
pnpm email devVisit http://localhost:3000 to preview all templates.
Send Test Email
import { getEmailService } from '@orbitusdev/core/services/email';
import { WelcomeEmail } from '@/emails/welcome';
const emailService = getEmailService();
await emailService.sendEmail({
to: 'test@example.com',
subject: 'Test Email',
react: WelcomeEmail({
username: 'Test User',
loginUrl: 'https://orbitus.dev/login'
})
});Error Handling
import { getEmailService } from '@orbitusdev/core/services/email';
import { logger } from '@orbitusdev/core/services/logger';
export async function sendEmailSafe(params: SendEmailParams) {
const emailService = getEmailService();
try {
const result = await emailService.sendEmail(params);
logger.info('Email sent successfully', { to: params.to, subject: params.subject });
return { success: true, data: result };
} catch (error) {
logger.error('Failed to send email', error, { to: params.to });
return { success: false, error: error.message };
}
}Related
Last updated on