Mailing
Learn how to send transactional emails in your Sushify Next.js application using React Email and various email providers
Sushify Next.js includes a powerful email system built with React Email that supports multiple email providers and offers beautifully designed, responsive email templates.
Features
- React Email Templates: Build beautiful, responsive emails using React components
- Multiple Providers: Support for Resend, Postmark, Mailgun, Plunk, and custom SMTP
- Internationalization: Automatic email translation support
- Type-Safe: Full TypeScript support with type-safe template parameters
- Easy Provider Switching: Change email providers with a single environment variable
- Preview Mode: Live preview your emails during development
Supported Providers
- Resend - Modern email API (Recommended)
- Postmark - Reliable transactional email
- Mailgun - Enterprise email service
- Plunk - Simple email API
- Nodemailer - Custom SMTP support
- Console - Development mode (logs emails to console)
Setup
1. Choose Your Email Provider
Select an email provider and configure it in your .env.local:
# Email Configuration
MAIL_PROVIDER="resend" # Options: resend, postmark, mailgun, plunk, nodemailer, console
MAIL_FROM="noreply@yourdomain.com"
# Provider-specific API keys (choose one):
# Resend
RESEND_API_KEY="re_..."
# Postmark
POSTMARK_API_KEY="..."
# Mailgun
MAILGUN_API_KEY="..."
MAILGUN_DOMAIN="mg.yourdomain.com"
# Plunk
PLUNK_API_KEY="..."
# Nodemailer (SMTP)
SMTP_HOST="smtp.gmail.com"
SMTP_PORT="587"
SMTP_USER="your-email@gmail.com"
SMTP_PASSWORD="your-password"2. Configure Mail Settings
Update your mail configuration in the config package:
export const config = {
// ...
mails: {
from: process.env.MAIL_FROM || "noreply@yourdomain.com",
provider: (process.env.MAIL_PROVIDER || "console") as MailProvider,
},
};Email Templates
The project includes pre-built email templates in packages/mail/emails/:
- EmailVerification - Verify user email addresses
- ForgotPassword - Password reset emails
- MagicLink - Passwordless authentication
- OrganizationInvitation - Team invitations
- NewsletterSignup - Newsletter confirmations
- LicenseRedemption - License key redemption
- NewUser - Welcome emails for new users
Sending Emails
Using Templates
Send an email using a pre-built template:
import { sendEmail } from "@repo/mail";
await sendEmail({
to: "user@example.com",
templateId: "emailVerification",
locale: "en",
context: {
username: "John Doe",
verificationUrl: "https://yourdomain.com/verify?token=...",
},
});Custom Emails
Send a custom email without using a template:
import { sendEmail } from "@repo/mail";
await sendEmail({
to: "user@example.com",
subject: "Welcome to Our Platform",
html: "<h1>Welcome!</h1><p>Thanks for joining us.</p>",
text: "Welcome! Thanks for joining us.",
});Creating Custom Templates
1. Create a New Template
Create a new React Email template in packages/mail/emails/:
import {
Body,
Container,
Head,
Heading,
Html,
Link,
Preview,
Text,
} from "@react-email/components";
interface CustomEmailProps {
username: string;
actionUrl: string;
locale: string;
translations: {
greeting: string;
callToAction: string;
};
}
export default function CustomEmail({
username,
actionUrl,
translations,
}: CustomEmailProps) {
return (
<Html>
<Head />
<Preview>{translations.greeting}</Preview>
<Body style={main}>
<Container style={container}>
<Heading style={h1}>{translations.greeting}</Heading>
<Text style={text}>
Hello {username},
</Text>
<Link href={actionUrl} style={button}>
{translations.callToAction}
</Link>
</Container>
</Body>
</Html>
);
}
// Styles
const main = {
backgroundColor: "#f6f9fc",
fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,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 button = {
backgroundColor: "#5469d4",
borderRadius: "4px",
color: "#fff",
fontSize: "16px",
textDecoration: "none",
textAlign: "center" as const,
display: "block",
padding: "12px",
};2. Register the Template
Add your template to packages/mail/emails/index.ts:
export { default as CustomEmail } from "./CustomEmail";3. Add Translations
Add translations in your locale files:
{
"customEmail": {
"subject": "Your Custom Subject",
"greeting": "Welcome to our platform!",
"callToAction": "Get Started"
}
}4. Use Your Template
await sendEmail({
to: "user@example.com",
templateId: "customEmail",
locale: "en",
context: {
username: "John Doe",
actionUrl: "https://yourdomain.com/action",
},
});Development
Preview Emails
Run the email preview server to see your templates in the browser:
cd packages/mail
pnpm previewThis will start a development server at http://localhost:3005 where you can preview all your email templates with live reload.
Export Static HTML
Export all templates as static HTML files:
cd packages/mail
pnpm exportThis generates HTML files in the packages/mail/out directory.
Provider Configuration
Resend (Recommended)
- Sign up at resend.com
- Create an API key
- Add your domain and verify DNS records
- Set environment variables:
MAIL_PROVIDER="resend"
RESEND_API_KEY="re_..."
MAIL_FROM="noreply@yourdomain.com"Postmark
- Sign up at postmarkapp.com
- Create a server and get your API token
- Add and verify your sender signature
- Set environment variables:
MAIL_PROVIDER="postmark"
POSTMARK_API_KEY="..."
MAIL_FROM="noreply@yourdomain.com"Mailgun
- Sign up at mailgun.com
- Add and verify your domain
- Get your API key
- Set environment variables:
MAIL_PROVIDER="mailgun"
MAILGUN_API_KEY="..."
MAILGUN_DOMAIN="mg.yourdomain.com"
MAIL_FROM="noreply@mg.yourdomain.com"Custom SMTP (Nodemailer)
For custom SMTP servers (Gmail, Outlook, etc.):
MAIL_PROVIDER="nodemailer"
SMTP_HOST="smtp.gmail.com"
SMTP_PORT="587"
SMTP_USER="your-email@gmail.com"
SMTP_PASSWORD="your-app-password"
MAIL_FROM="your-email@gmail.com"Console (Development)
For development, use the console provider to log emails instead of sending them:
MAIL_PROVIDER="console"Error Handling
The mail package includes structured error handling:
import { sendEmail, MailError } from "@repo/mail";
try {
await sendEmail({
to: "user@example.com",
templateId: "emailVerification",
context: { /* ... */ },
});
} catch (error) {
if (error instanceof MailError) {
console.error("Mail error:", error.code, error.message);
console.error("Provider:", error.provider);
console.error("Context:", error.context);
}
}Best Practices
- Use Templates: Always use templates for consistency and maintainability
- Test Locally: Use the preview server to test your emails before deployment
- Internationalization: Provide translations for all email content
- Responsive Design: Use React Email components to ensure mobile responsiveness
- Plain Text: Always include plain text versions for better deliverability
- Sender Verification: Verify your sender domain/email with your provider
- Rate Limiting: Implement rate limiting for user-triggered emails
- Error Logging: Log email errors for debugging and monitoring
API Reference
sendEmail()
function sendEmail<T extends TemplateId>(params: {
to: string;
locale?: string;
} & (
| {
templateId: T;
context: TemplateContext<T>;
}
| {
subject: string;
text?: string;
html?: string;
}
)): Promise<boolean>;Parameters:
to- Recipient email addresslocale- (Optional) Locale for email translationstemplateId- ID of the template to usecontext- Template-specific context datasubject- Custom email subject (when not using template)html- Custom HTML content (when not using template)text- Custom plain text content (when not using template)
Returns: Promise<boolean> - true if email was sent successfully