npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mailer-easy

v1.0.0

Published

Type-safe email templates with React Email and Zod validation

Readme

Mail System 📧

A modern, type-safe email service built with Next.js, React Email, and Nodemailer. This FOSS (Free and Open Source Software) project provides a robust API for sending transactional emails with beautiful, customizable templates.

License: MIT Next.js TypeScript

✨ Features

  • 🎨 Beautiful Email Templates: Pre-built, responsive email templates using React Email components
  • 🔒 Type-Safe: Full TypeScript support with Zod schema validation
  • 📝 Template Registry: Centralized template management system
  • ⚡ Fast & Modern: Built on Next.js 15 with React 19
  • 🔐 Secure: Built-in security with server identity verification
  • 🎯 Flexible: Easy to customize and extend with new templates
  • 📦 Production Ready: Includes error handling, validation, and logging

📋 Prerequisites

Before you begin, ensure you have the following installed:

  • Node.js: Version 18.x or higher
  • npm, yarn, or pnpm: Package manager (pnpm recommended)
  • SMTP Server: Access to an SMTP server (e.g., Gmail, SendGrid, Sendinblue)

🚀 Quick Start

1. Clone the Repository

git clone https://github.com/kanakkholwal/mail-system.git
cd mail-system

2. Install Dependencies

npm install
# or
yarn install
# or
pnpm install

3. Configure Environment Variables

Copy the example environment file and configure your settings:

cp .env.example .env

Edit .env with your SMTP credentials:

# SMTP Configuration
[email protected]
MAIL_PASSWORD=your-smtp-password
SMTP_HOST=smtp-relay.sendinblue.com

# Security
SERVER_IDENTITY=your-secure-random-key

# Optional
NODE_ENV=development

4. Run the Development Server

npm run dev

The server will start at http://localhost:3000

🔧 Configuration

Environment Variables

| Variable | Required | Default | Description | |----------|----------|---------|-------------| | MAIL_EMAIL | ✅ | [email protected] | SMTP email address | | MAIL_PASSWORD | ✅ | - | SMTP password/app password | | SMTP_HOST | ❌ | smtp-relay.sendinblue.com | SMTP server host | | SERVER_IDENTITY | ✅ | - | Security key for API authentication | | NODE_ENV | ❌ | development | Environment mode |

SMTP Configuration

The system supports any SMTP provider. Common configurations:

Gmail:

SMTP_HOST=smtp.gmail.com
[email protected]
MAIL_PASSWORD=your-app-password

SendGrid:

SMTP_HOST=smtp.sendgrid.net
MAIL_EMAIL=apikey
MAIL_PASSWORD=your-sendgrid-api-key

Sendinblue (Brevo):

SMTP_HOST=smtp-relay.sendinblue.com
[email protected]
MAIL_PASSWORD=your-smtp-key

📨 API Usage

Send Email Endpoint

Endpoint: POST /api/send

Request Body:

{
  "template_key": "welcome_verify",
  "targets": ["[email protected]"],
  "subject": "Welcome to Our Platform!",
  "payload": {
    "name": "John Doe",
    "email": "[email protected]",
    "verificationUrl": "https://example.com/verify?token=abc123"
  }
}

Response (Success):

{
  "data": ["[email protected]"]
}

Response (Error):

{
  "error": "Template Validation Failed",
  "message": "Invalid payload for template"
}

Example cURL Request

curl -X POST http://localhost:3000/api/send \
  -H "Content-Type: application/json" \
  -d '{
    "template_key": "welcome_verify",
    "targets": ["[email protected]"],
    "subject": "Welcome!",
    "payload": {
      "name": "John Doe",
      "email": "[email protected]",
      "verificationUrl": "https://example.com/verify?token=abc123"
    }
  }'

Example JavaScript/Node.js Request

const response = await fetch('http://localhost:3000/api/send', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    template_key: 'welcome_verify',
    targets: ['[email protected]'],
    subject: 'Welcome to Our Platform!',
    payload: {
      name: 'John Doe',
      email: '[email protected]',
      verificationUrl: 'https://example.com/verify?token=abc123'
    }
  })
});

const result = await response.json();
console.log(result);

📧 Available Email Templates

1. Welcome & Verification Email (welcome_verify)

Purpose: Welcome new users and verify their email address.

Required Payload:

{
  name: string;              // User's name
  email: string;             // User's email address
  verificationUrl: string;   // URL for email verification
  branding?: {               // Optional branding override
    name?: string;
    logoUrl?: string;
    websiteUrl?: string;
    primaryColor?: string;
  }
}

2. Password Reset Email (reset_password)

Purpose: Send password reset instructions to users.

Required Payload:

{
  name: string;              // User's name
  email: string;             // User's email address
  resetUrl: string;          // URL for password reset
  branding?: {               // Optional branding override
    name?: string;
    logoUrl?: string;
    websiteUrl?: string;
    primaryColor?: string;
  }
}

🎨 Creating Custom Templates

Step 1: Create Template Component

Create a new directory in emails/templates/:

mkdir emails/templates/my-template

Create index.tsx:

import { Button } from "@emails/kit/components/button";
import { Layout } from "@emails/kit/components/layout";
import { H1, BodyText } from "@emails/kit/components/typography";
import { Section } from "@react-email/components";
import { MyTemplateProps } from "./schema";

export const MyTemplate = ({ name, actionUrl }: MyTemplateProps) => {
  return (
    <Layout previewText="Your custom email">
      <Section className="my-6">
        <H1>Hello {name}!</H1>
        <BodyText>This is your custom email template.</BodyText>
        <Button href={actionUrl}>Take Action</Button>
      </Section>
    </Layout>
  );
};

export default MyTemplate;

Step 2: Define Schema

Create schema.ts:

import { z } from "zod";

export const myTemplateSchema = z.object({
  name: z.string(),
  actionUrl: z.string().url(),
});

export type MyTemplateProps = z.infer<typeof myTemplateSchema>;

Step 3: Register Template

Update emails/registry.ts:

import MyTemplate from "./templates/my-template";
import { myTemplateSchema } from "./templates/my-template/schema";

export const registry = {
  // ... existing templates
  "my_template": {
    component: MyTemplate,
    schema: myTemplateSchema,
  },
} as const;

Step 4: Use Your Template

curl -X POST http://localhost:3000/api/send \
  -H "Content-Type: application/json" \
  -d '{
    "template_key": "my_template",
    "targets": ["[email protected]"],
    "subject": "Custom Email",
    "payload": {
      "name": "John",
      "actionUrl": "https://example.com/action"
    }
  }'

🏗️ Project Structure

mail-system/
├── app/
│   ├── api/
│   │   └── send/
│   │       └── route.ts          # Email sending API endpoint
│   └── layout.tsx                # Root layout
├── emails/
│   ├── kit/                      # Reusable email components
│   │   ├── components/           # Button, Header, Footer, etc.
│   │   ├── tailwind.ts           # Tailwind configuration
│   │   ├── tokens.ts             # Design tokens
│   │   └── types.ts              # TypeScript types
│   ├── templates/                # Email templates
│   │   ├── welcome-verify/
│   │   └── reset-password/
│   ├── helper.ts                 # Email sending helper functions
│   ├── registry.ts               # Template registry
│   ├── renderer.tsx              # Template renderer
│   └── schema.ts                 # Zod schemas
├── .env.example                  # Example environment variables
├── next.config.ts                # Next.js configuration
├── package.json                  # Dependencies and scripts
├── project.config.ts             # Project configuration
├── tsconfig.json                 # TypeScript configuration
└── README.md                     # This file

🛠️ Development

Available Scripts

# Start development server
npm run dev

# Build for production
npm run build

# Start production server
npm run start

# Lint code
npm run lint

# Format code
npm run format

Code Style

This project uses:

  • TypeScript for type safety
  • Zod for runtime validation
  • Prettier for code formatting
  • ESLint for code linting

Adding New Features

  1. Create a new branch: git checkout -b feature/your-feature
  2. Make your changes
  3. Run linting: npm run lint
  4. Format code: npm run format
  5. Test your changes thoroughly
  6. Commit with clear messages
  7. Push and create a Pull Request

🤝 Contributing

Contributions are welcome! Here's how you can help:

Reporting Bugs

  1. Check if the bug has already been reported
  2. Create a new issue with a clear title and description
  3. Include steps to reproduce
  4. Add relevant logs or screenshots

Suggesting Enhancements

  1. Open an issue describing the enhancement
  2. Explain why this enhancement would be useful
  3. Provide examples if possible

Pull Requests

  1. Fork the repository
  2. Create your feature branch
  3. Make your changes following our coding standards
  4. Add or update tests if needed
  5. Ensure all tests pass
  6. Update documentation as needed
  7. Submit a pull request

Code of Conduct

  • Be respectful and inclusive
  • Provide constructive feedback
  • Focus on what's best for the community
  • Show empathy towards other contributors

🐛 Troubleshooting

Common Issues

Issue: "SMTP Authentication Failed"

  • Verify your SMTP credentials are correct
  • For Gmail, ensure you're using an App Password, not your regular password
  • Check if 2FA is enabled on your email account

Issue: "Template not found in registry"

  • Verify the template_key matches exactly with registry keys
  • Check the spelling and case sensitivity
  • Ensure the template is properly registered in emails/registry.ts

Issue: "Invalid payload for template"

  • Check that all required fields are provided
  • Verify field types match the schema
  • Review the Zod validation error messages in the response

Issue: "Port 3000 already in use"

  • Kill the process using port 3000: lsof -ti:3000 | xargs kill -9
  • Or use a different port: PORT=3001 npm run dev

Getting Help

  • 📖 Check the documentation
  • 💬 Open an issue on GitHub
  • 📧 Contact the maintainers

📚 Additional Resources

📄 License

This project is licensed under the MIT License - see below for details:

MIT License

Copyright (c) 2024 Nexonauts

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

🙏 Acknowledgments

📞 Support

If you find this project helpful, please consider:

  • ⭐ Starring the repository
  • 🐛 Reporting bugs
  • 💡 Suggesting new features
  • 🤝 Contributing to the codebase
  • 📢 Sharing with others

Made with ❤️ by the Nexonauts team