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

composa

v1.2.1

Published

Compose beautiful multilingual emails with XHTML templates and Nodemailer

Readme

🎨 Composa

npm version Downloads License: MIT Node.js Version TypeScript

Compose beautiful multilingual emails with XHTML templates and Nodemailer integration. Full TypeScript support included!

Features

  • Multilingual Support - Built-in French and English templates
  • Professional Templates - Pre-designed XHTML email templates
  • Easy Configuration - Simple setup with Nodemailer
  • Interactive CLI - Guided setup for email providers with step-by-step instructions
  • Multiple Providers - Support for Gmail, Yahoo, AOL, GMX, Zoho, iCloud, Outlook, SendGrid, Mailgun
  • Template Engine - Variable interpolation and conditional rendering
  • Ready-to-use - Pre-built templates for common use cases
  • Modern ESM - ES modules with async/await support
  • Component-based Flow - Compose templates like components (compileTemplate → compileMail → sendMail)
  • Security First - Built-in warnings and best practices for credential management
  • TypeScript Support - Full type definitions with IntelliSense and compile-time checking

Available Templates

| Template | French | English | Use Case | | --------------------------- | ------ | ------- | ------------------------ | | password-reset | ✅ | ✅ | Password reset emails | | account-creation | ✅ | ✅ | Welcome new users | | suspicious-login | ✅ | ✅ | Security alerts | | subscription-confirmation | ✅ | ✅ | Newsletter subscriptions | | newsletter-promotion | ✅ | ✅ | Marketing campaigns | | scheduled-maintenance | ✅ | ✅ | System notifications |

Quick Start

Installation

npm install composa

JavaScript Usage

import { EmailClient, defaultSubjects, createGmailConfig } from "composa";

const mailer = new EmailClient({
  defaultLang: "fr",
  subjects: defaultSubjects,
  transport: createGmailConfig("[email protected]", "your-app-password"),
});

// New flow: compileMail → sendMail
const { html, subject } = mailer.compileMail("password-reset", {
  lang: "fr",
  variables: {
    USER_NAME: "Jean Dupont",
    USER_EMAIL: "[email protected]",
    RESET_URL: "https://yourapp.com/reset/token123",
    EXPIRATION_TIME: "24 heures",
  },
});

const result = await mailer.sendMail({
  to: "[email protected]",
  html,
  subject,
});

console.log("Email sent:", result);

TypeScript Usage

import { EmailClient, createGmailConfig, type EmailClientOptions, type MailOptions } from "composa";

const options: EmailClientOptions = {
  defaultLang: "fr",
  defaultFrom: "[email protected]",
  transport: createGmailConfig("[email protected]", "your-app-password"),
};

const mailer = new EmailClient(options);

const mailOptions: MailOptions = {
  to: "[email protected]",
  subject: "Welcome!",
  html: "<h1>Welcome to our app!</h1>"
};

const result = await mailer.send(mailOptions);

TypeScript Support: Composa includes full TypeScript definitions with IntelliSense, compile-time checking, and type safety. See TYPESCRIPT.md for detailed TypeScript usage examples.

Component-based Flow

Composa uses a component-like approach where you can compose templates step by step:

Flow Overview

  1. compileTemplate - Compile individual templates (like components)
  2. compileMail - Combine templates into a complete email (HTML + subject)
  3. sendMail - Send the final composed email

Advanced Example - Template Composition

// Compile individual components
const headerHtml = mailer.compileTemplate("email-header", {
  variables: { APP_NAME: "MyApp", USER_NAME: "John" },
});

const itemListHtml = items
  .map((item) =>
    mailer.compileTemplate("list-item", {
      variables: { NAME: item.name, PRICE: item.price },
    }),
  )
  .join("");

// Compose the main email
const { html, subject } = mailer.compileMail("newsletter", {
  variables: {
    HEADER: headerHtml,
    ITEM_LIST: `<ul>${itemListHtml}</ul>`,
    FOOTER: mailer.compileTemplate("email-footer", {}),
  },
});

// Send the composed email
await mailer.sendMail({ to: "[email protected]", html, subject });

Email Providers

Composa supports multiple email providers with easy configuration:

Gmail Configuration

import { createGmailConfig } from "composa";

const gmailConfig = createGmailConfig("[email protected]", "your-app-password");
const mailer = new EmailClient({ transport: gmailConfig });

Setup Steps:

  1. Enable 2-Factor Authentication on your Google account
  2. Go to Google Account settings > Security > 2-Step Verification
  3. Generate an 'App Password' for 'Mail'
  4. Use your Gmail address and the App Password (not your regular password)

Other Providers

import { 
  createYahooConfig, 
  createOutlookConfig,
  createSendGridConfig,
  createMailgunConfig,
  createAOLConfig,
  createGMXConfig,
  createZohoConfig,
  createiCloudConfig
} from "composa";

// Yahoo (requires App Password)
const yahoo = createYahooConfig("[email protected]", "your-app-password");

// Outlook
const outlook = createOutlookConfig("[email protected]", "your-password");

// SendGrid
const sendgrid = createSendGridConfig("your-sendgrid-api-key");

// Mailgun
const mailgun = createMailgunConfig("your-mailgun-api-key", "your-domain");

// AOL (requires App Password)
const aol = createAOLConfig("[email protected]", "your-app-password");

// GMX
const gmx = createGMXConfig("[email protected]", "your-password");

// Zoho
const zoho = createZohoConfig("[email protected]", "your-password");

// iCloud (requires App Password)
const icloud = createiCloudConfig("[email protected]", "your-app-password");

Advanced Usage

Bulk Sending

const recipients = ["[email protected]", "[email protected]", "[email protected]"];

const results = await mailer.sendBulk(recipients, {
  subject: "Weekly Newsletter",
  html: "<h1>Newsletter</h1><p>Check out our latest updates!</p>"
});

results.forEach(result => {
  if (result.success) {
    console.log(`✅ Email sent to ${result.recipient}`);
  } else {
    console.log(`❌ Failed to send to ${result.recipient}: ${result.error}`);
  }
});

Retry Logic

const result = await mailer.sendWithRetry({
  to: "[email protected]",
  subject: "Important Email",
  html: "<h1>Important Information</h1>"
}, 3); // Max 3 retries

if (result.success) {
  console.log("Email sent successfully:", result.messageId);
} else {
  console.log("Email failed after retries:", result.error);
}

Template Management

// List available templates
const availableTemplates = mailer.listAvailableTemplates("fr");
console.log("Available templates:", availableTemplates);

// Check if template exists
const exists = mailer.templateExists("password-reset", "fr");
console.log("Template exists:", exists);

// Get template information
const info = mailer.getTemplateInfo("password-reset", "fr");
console.log("Template info:", info);

// Register custom template at runtime
const customTemplate = `
  <div style="background: {{USER_COLOR}};">
    <h1>Hello {{USER_NAME}}!</h1>
    <p>Your favorite color is {{USER_COLOR}}.</p>
  </div>
`;

mailer.registerTemplateString("user-welcome", customTemplate, "fr");

// Clear template cache
mailer.clearCache();

Template Directory Structure

your-project/
├── templates/
│   ├── en-EN/
│   │   ├── welcome.xhtml
│   │   └── invoice.xhtml
│   └── fr-FR/
│       ├── welcome.xhtml
│       └── invoice.xhtml

Custom Templates

You can create your own templates by adding .xhtml files to the templates directory:

// Set custom templates path
const mailer = new EmailClient({
  templatesPath: "./my-custom-templates",
  defaultLang: "en"
});

Template Variables

Use {{VARIABLE_NAME}} syntax in your templates:

<!-- templates/en-EN/welcome.xhtml -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Welcome to {{APP_NAME}}</title>
</head>
<body>
    <h1>Welcome {{USER_NAME}}!</h1>
    <p>Thank you for joining {{APP_NAME}}.</p>
    <p>Your email: {{USER_EMAIL}}</p>
    <p>Visit us at: <a href="{{APP_URL}}">{{APP_URL}}</a></p>
    <p>Need help? Contact us at {{SUPPORT_EMAIL}}</p>
</body>
</html>

Template Subjects

Register subjects for your custom templates:

// Register subjects for custom templates
mailer.registerSubject("welcome", "en", "Welcome to {{APP_NAME}}, {{USER_NAME}}!");
mailer.registerSubject("welcome", "fr", "Bienvenue sur {{APP_NAME}}, {{USER_NAME}} !");

// Or register multiple subjects at once
mailer.registerSubjects("welcome", {
  en: "Welcome to {{APP_NAME}}, {{USER_NAME}}!",
  fr: "Bienvenue sur {{APP_NAME}}, {{USER_NAME}} !",
  es: "¡Bienvenido a {{APP_NAME}}, {{USER_NAME}}!"
});

Dynamic Template Registration

Register templates at runtime without files:

// Register a template string in memory
const customTemplate = `
  <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
    <h1 style="color: {{USER_COLOR}};">Hello {{USER_NAME}}!</h1>
    <p>Your favorite color is {{USER_COLOR}}.</p>
    <p>Account created: {{CREATION_DATE}}</p>
  </div>
`;

mailer.registerTemplateString("user-welcome", customTemplate, "en");

// Use the registered template
const { html, subject } = mailer.compileMail("user-welcome", {
  variables: {
    USER_NAME: "John Doe",
    USER_COLOR: "#007bff",
    CREATION_DATE: new Date().toLocaleDateString()
  }
});

Template Inheritance and Composition

Create reusable template components:

// Base template: templates/en-EN/email-base.xhtml
const baseTemplate = `
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>{{PAGE_TITLE}}</title>
  </head>
  <body style="font-family: Arial, sans-serif;">
    <header style="background: #f8f9fa; padding: 20px;">
      <h1>{{APP_NAME}}</h1>
    </header>
    <main style="padding: 20px;">
      {{CONTENT}}
    </main>
    <footer style="background: #f8f9fa; padding: 20px; text-align: center;">
      <p>&copy; {{CURRENT_YEAR}} {{APP_NAME}}. All rights reserved.</p>
    </footer>
  </body>
  </html>
`;

mailer.registerTemplateString("email-base", baseTemplate, "en");

// Content template: templates/en-EN/newsletter-content.xhtml
const contentTemplate = `
  <h2>Newsletter - {{NEWSLETTER_TITLE}}</h2>
  <p>{{NEWSLETTER_CONTENT}}</p>
  <ul>
    {{NEWSLETTER_ITEMS}}
  </ul>
`;

mailer.registerTemplateString("newsletter-content", contentTemplate, "en");

// Compose the final email
const content = mailer.compileTemplate("newsletter-content", {
  variables: {
    NEWSLETTER_TITLE: "Weekly Updates",
    NEWSLETTER_CONTENT: "Here are this week's highlights:",
    NEWSLETTER_ITEMS: items.map(item => `<li>${item.title}</li>`).join("")
  }
});

const { html, subject } = mailer.compileMail("email-base", {
  variables: {
    PAGE_TITLE: "Weekly Newsletter",
    CONTENT: content
  }
});

Template Validation and Error Handling

// Check if template exists before using
if (mailer.templateExists("custom-template", "en")) {
  const { html, subject } = mailer.compileMail("custom-template", {
    variables: { USER_NAME: "John" }
  });
} else {
  console.error("Template 'custom-template' not found for language 'en'");
}

// Get detailed template information
const templateInfo = mailer.getTemplateInfo("custom-template", "en");
console.log("Template info:", {
  name: templateInfo.name,
  language: templateInfo.lang,
  exists: templateInfo.exists,
  source: templateInfo.source, // 'memory', 'disk', or 'none'
  cached: templateInfo.cached,
  path: templateInfo.path
});

Configuration Testing

const config = await mailer.testConfiguration();
console.log("Configuration test results:");
console.log(`SMTP: ${config.smtp ? '✅ Working' : '❌ Failed'}`);
console.log(`DKIM: ${config.dkim ? '✅ Enabled' : '❌ Disabled'}`);
console.log(`Host: ${config.host}:${config.port} (${config.secure ? 'Secure' : 'Insecure'})`);
console.log(`Sender: ${config.sender}`);
console.log(`Default Language: ${config.defaultLang}`);

Environment Variables

You can configure Composa using environment variables:

# SMTP Configuration
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
[email protected]
SMTP_PASSWORD=your-app-password

# DKIM Configuration (optional)
DKIM_DOMAIN=yourdomain.com
DKIM_SELECTOR=default
DKIM_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----...

# Default sender
[email protected]
// Use environment variables
const mailer = new EmailClient({
  defaultLang: "en",
  // Transport will be created from environment variables
});

CLI Tool

Composa includes an interactive CLI for easy setup:

npx composa setup

This will guide you through:

  • Provider selection
  • Credential configuration
  • Template setup
  • Testing your configuration

TypeScript Support

Composa includes comprehensive TypeScript definitions:

  • IntelliSense - Full auto-completion in your IDE
  • Type Safety - Compile-time error checking
  • Documentation - Inline help and parameter hints
  • Refactoring - Safe renaming and code changes

TypeScript Examples

import { 
  EmailClient, 
  createGmailConfig, 
  type EmailClientOptions, 
  type MailOptions,
  type SendResult,
  type BulkSendResult 
} from "composa";

// Type-safe configuration
const options: EmailClientOptions = {
  defaultFrom: "[email protected]",
  defaultLang: "en",
  defaults: {
    APP_NAME: "My App",
    APP_URL: "https://myapp.com"
  },
  transporter: createGmailConfig("[email protected]", "your-app-password")
};

const client = new EmailClient(options);

// Type-safe email sending
const mailOptions: MailOptions = {
  to: "[email protected]",
  subject: "Welcome!",
  html: "<h1>Welcome to our app!</h1>"
};

const result: Promise<SendResult> = client.send(mailOptions);

See TYPESCRIPT.md for detailed TypeScript usage examples and advanced patterns.

Examples

Check out the examples directory for more usage patterns:

Documentation

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • Built with Nodemailer
  • Inspired by modern email best practices
  • Templates designed for accessibility and compatibility

Support


Made with ❤️ by Puparia