{"id":25980051,"url":"https://github.com/juanses03/waitlist-mailer","last_synced_at":"2025-03-05T07:26:01.557Z","repository":{"id":277255198,"uuid":"931833146","full_name":"Juanses03/waitlist-mailer","owner":"Juanses03","description":"A tool to manage waitlists and send confirmation emails.","archived":false,"fork":false,"pushed_at":"2025-03-04T03:46:27.000Z","size":19655,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-04T04:29:07.611Z","etag":null,"topics":["github","nodejs","npm-package","open-source"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Juanses03.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-12T23:37:05.000Z","updated_at":"2025-03-04T03:46:30.000Z","dependencies_parsed_at":null,"dependency_job_id":"aafcb58a-80a3-4be4-bda2-f124638fdeef","html_url":"https://github.com/Juanses03/waitlist-mailer","commit_stats":null,"previous_names":["juanses03/waitlist-mailer"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Juanses03%2Fwaitlist-mailer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Juanses03%2Fwaitlist-mailer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Juanses03%2Fwaitlist-mailer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Juanses03%2Fwaitlist-mailer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Juanses03","download_url":"https://codeload.github.com/Juanses03/waitlist-mailer/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241985103,"owners_count":20053025,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["github","nodejs","npm-package","open-source"],"created_at":"2025-03-05T07:26:00.450Z","updated_at":"2025-03-05T07:26:01.544Z","avatar_url":"https://github.com/Juanses03.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WaitlistMailer\n\n[![npm project link](https://img.shields.io/badge/npm-waitlist--mailer-red.svg)](https://www.npmjs.com/package/waitlist-mailer)  \n[![GitHub](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)  \n[![Version](https://img.shields.io/badge/version-1.0.0-green.svg)](https://www.npmjs.com/package/waitlist-mailer)  \n[![Nodejs](https://img.shields.io/badge/node.js-%3E%3D14-blue.svg)](https://nodejs.org)  \n[![MongoDB](https://img.shields.io/badge/MongoDB-supported-green.svg)](https://www.mongodb.com)  \n[![PostgreSQL/MySQL](https://img.shields.io/badge/PostgreSQL%2FMySQL-supported-green.svg)](https://www.postgresql.org)  \n[![Downloads](https://img.shields.io/npm/dt/waitlist-mailer.svg)](https://www.npmjs.com/package/waitlist-mailer)  \n\n**WaitlistMailer** is a TypeScript-based NPM package for managing waitlists and sending confirmation emails. It supports **local**, **MongoDB**, and **SQL (PostgreSQL/MySQL)** storage, with **customizable HTML templates**, an **event-driven architecture**, and advanced features like **bulk sending**, **automatic retries**, **Joi validation**, and **query capabilities**.\n\nThe **1.0.0 version** introduces **bulk email sending**, **indexed database storage**, and **advanced queries**.\n\n---\n\n## Table of Contents\n\n- [Description](#description)  \n- [Key Features](#key-features)  \n- [Installation](#installation)  \n- [Usage](#usage)  \n  - [Initial Setup](#initial-setup)  \n  - [Adding Emails to the Waitlist](#adding-emails-to-the-waitlist)  \n  - [Removing Emails](#removing-emails)  \n  - [Viewing the Waitlist](#viewing-the-waitlist)  \n  - [Clearing the Waitlist](#clearing-the-waitlist)  \n  - [Sending Confirmation Emails](#sending-confirmation-emails)  \n  - [Bulk Email Sending](#bulk-email-sending)  \n  - [Saving the Waitlist](#saving-the-waitlist)  \n  - [Advanced Queries](#advanced-queries)  \n  - [Event Handling](#event-handling)  \n  - [Closing Resources](#closing-resources)  \n- [API](#api)  \n- [Common Errors](#common-errors)  \n- [Contributions](#contributions)  \n- [License](#license)  \n- [Version History](#version-history)  \n\n---\n\n## Description\n\n**WaitlistMailer** simplifies waitlist management in **Node.js** with robust email validation, flexible storage options, and efficient email delivery via **Nodemailer**. It's designed for scalability and ease of use, supporting both in-memory and persistent storage with MongoDB or SQL databases.\n\n**Version 1.0.0** adds:\n- **Bulk email sending** for efficient mass communication  \n- **Indexed MongoDB and SQL storage** for optimized performance  \n- **Advanced queries** for searching and aggregating waitlist data  \n\n---\n\n## Key Features\n\n- **Email Validation**: Strict validation using Joi  \n- **Storage Options**: Local (in-memory), MongoDB (`Waitlist` collection), or SQL (`waitlist` table)  \n- **Dynamic Templates**: HTML emails with inline or file-based templates  \n- **Nodemailer Integration**: Reliable SMTP delivery  \n- **Event-Driven**: Emits events like `onEmailSent`, `onBulkConfirmationComplete`  \n- **Retries**: Automatic retry for failed email sends  \n- **Bulk Sending**: Mass emailing with retry support (v1.0.0)  \n- **Database Indexing**: Indexed `email` and `createdAt` fields (v1.0.0)  \n- **Advanced Queries**: Pattern-based search and date range counting (v1.0.0)  \n\n\u003e ⚠️ **Note**: Requires Node.js \u003e= 14. Install via `npm install waitlist-mailer`.\n\n---\n\n## Installation\n\n```bash\nnpm install waitlist-mailer@1.0.0 nodemailer joi events mongoose sequelize pg mysql2\n```\n\n### Dependencies\n- **nodemailer**: Email sending  \n- **joi**: Email validation  \n- **mongoose**: MongoDB support (optional)  \n- **sequelize, pg, mysql2**: SQL support (optional)\n\n### Environment Variables\nCreate a `.env.local` file:\n\n```ini\nSMTP_HOST=smtp.gmail.com\nSMTP_PORT=587\nSMTP_USER=your-email@gmail.com\nSMTP_PASS=your-app-password\nMONGO_URI=mongodb://localhost:27017/waitlistdb\nSQL_DIALECT=mysql\nSQL_HOST=localhost\nSQL_PORT=3306\nSQL_USER=root\nSQL_PASSWORD=\nSQL_DATABASE=waitlistdb\n```\n\n---\n\n## Usage\n\n### Initial Setup\nInitialize with storage type (local, db, or sql) and configuration:\n\n```typescript\nimport WaitlistMailer from 'waitlist-mailer';\n\nconst mailConfig = {\n  host: process.env.SMTP_HOST!,\n  port: parseInt(process.env.SMTP_PORT!),\n  user: process.env.SMTP_USER!,\n  pass: process.env.SMTP_PASS!,\n};\n\n// SQL Example\nconst mailer = new WaitlistMailer('sql', mailConfig, {\n  companyName: 'My Company',\n  sqlConfig: {\n    dialect: 'mysql',\n    host: process.env.SQL_HOST!,\n    port: parseInt(process.env.SQL_PORT!),\n    username: process.env.SQL_USER!,\n    password: process.env.SQL_PASSWORD!,\n    database: process.env.SQL_DATABASE!,\n  },\n});\n\n// MongoDB Example\n// const mailer = new WaitlistMailer('db', mailConfig, { mongoUri: process.env.MONGO_URI! });\n\n// Local Example\n// const mailer = new WaitlistMailer('local', mailConfig);\n\nawait mailer.waitForInitialization(); // Wait for DB connection if applicable\n```\n\n### Adding Emails to the Waitlist\n\n```typescript\nconst success = mailer.addEmail('user@example.com');\nconsole.log(success ? 'Email added' : 'Failed (invalid or duplicate)');\n```\n\n### Removing Emails\n\n```typescript\nconst removed = mailer.removeEmail('user@example.com');\nconsole.log(removed ? 'Email removed' : 'Email not found');\n```\n\n### Viewing the Waitlist\n\n```typescript\nconst emails = mailer.getWaitlist();\nconsole.log('Current waitlist:', emails);\n```\n\n### Clearing the Waitlist\n\n```typescript\nmailer.clearWaitlist();\nconsole.log('Waitlist cleared');\n```\n\n### Sending Confirmation Emails\n\n#### Using Template Functions\n\n```typescript\nconst subjectTemplate = (email: string) =\u003e `Welcome, ${email}!`;\nconst bodyTemplate = (email: string) =\u003e `\u003ch1\u003eHello ${email}\u003c/h1\u003e\u003cp\u003eWelcome to [Company Name]!\u003c/p\u003e`;\n\nconst sent = await mailer.sendConfirmation('user@example.com', subjectTemplate, bodyTemplate);\nconsole.log(sent ? 'Email sent' : 'Failed to send');\n```\n\n#### Using HTML Files\nCreate `templates/confirmation.html`:\n\n```html\n\u003ch1\u003eWelcome, {{email}}!\u003c/h1\u003e\n\u003cp\u003eThanks for joining {{companyName}}. {{customMessage}}\u003c/p\u003e\n```\n\n```typescript\nconst sent = await mailer.sendConfirmationFromFile(\n  'user@example.com',\n  (email) =\u003e `Welcome, ${email}!`,\n  './templates/confirmation.html',\n  { customMessage: 'We're excited to have you!' }\n);\nconsole.log(sent ? 'Email sent' : 'Failed to send');\n```\n\n#### With Retries\n\n```typescript\nconst sent = await mailer.sendConfirmationWithRetry(\n  'user@example.com',\n  (email) =\u003e `Welcome, ${email}!`,\n  (email) =\u003e `\u003cp\u003eHello ${email}\u003c/p\u003e`,\n  3, // retries\n  1000 // delay in ms\n);\nconsole.log(sent ? 'Email sent after retries' : 'Failed after retries');\n```\n\n### Bulk Email Sending\n\n```typescript\nconst subjectFn = (email) =\u003e `Hello, ${email}!`;\nconst bodyFn = (email) =\u003e `\u003ch1\u003eWelcome\u003c/h1\u003e\u003cp\u003eJoin us, ${email}!\u003c/p\u003e`;\n\nconst successCount = await mailer.sendBulkConfirmation(subjectFn, bodyFn, 3, 1000);\nconsole.log(`Sent to ${successCount} users`);\n```\n\n⚠️ **Warning**: Check SMTP rate limits (e.g., Gmail: 500/day).\n\n### Saving the Waitlist\n\n```typescript\nconst saved = await mailer.saveWaitlist();\nconsole.log(saved ? 'Waitlist saved' : 'Failed to save');\n```\n\n### Advanced Queries\n\n#### Find Emails by Pattern\n\n```typescript\nconst matches = await mailer.findEmailsByPattern('example');\nconsole.log('Matching emails:', matches); // e.g., ['user@example.com']\n```\n\n#### Count by Date Range\n\n```typescript\nconst count = await mailer.countWaitlistByDate(\n  new Date('2023-01-01'),\n  new Date('2023-12-31')\n);\nconsole.log(`Emails in 2023: ${count}`);\n```\n\n### Event Handling\n\n```typescript\nmailer.on('onEmailAdded', (email) =\u003e console.log(`Added: ${email}`));\nmailer.on('onEmailRemoved', (email) =\u003e console.log(`Removed: ${email}`));\nmailer.on('onEmailSent', (email, info) =\u003e console.log(`Sent to ${email}: ${info.messageId}`));\nmailer.on('onBulkConfirmationComplete', ({ successCount, total }) =\u003e console.log(`Bulk: ${successCount}/${total}`));\nmailer.on('onWaitlistSaved', (emails) =\u003e console.log('Saved:', emails));\nmailer.on('onError', ({ email, action, error }) =\u003e console.error(`Error in ${action} for ${email}:`, error));\n```\n\n### Closing Resources\n\n```typescript\nawait mailer.close();\nconsole.log('Resources closed');\n```\n\n---\n\n## API\n\n### Constructor\n\n```typescript\nnew WaitlistMailer(storage: 'local' | 'db' | 'sql', mailConfig: MailConfig, options?: WaitlistMailerOptions)\n```\n- **storage**: Storage type (default: 'local')\n- **mailConfig**: { host: string, port: number, user: string, pass: string }\n- **options**: { companyName?: string, mongoUri?: string, sqlConfig?: { dialect: 'postgres' | 'mysql', host: string, port: number, username: string, password: string, database: string } }\n\n### Methods\n\n| Method | Description | Returns |\n|--------|-------------|---------|\n| addEmail(email: string) | Adds a validated, unique email | boolean |\n| removeEmail(email: string) | Removes an email if it exists | boolean |\n| getWaitlist() | Returns all emails as an array | string[] |\n| clearWaitlist() | Clears in-memory and persistent waitlist | void |\n| isInitialized() | Checks if initialization is complete | boolean |\n| waitForInitialization() | Waits for async setup to finish | Promise\u003cvoid\u003e |\n| sendConfirmation(email, subjectTemplate, bodyTemplate) | Sends an email with templates | Promise\u003cboolean\u003e |\n| sendConfirmationFromFile(email, subjectTemplate, templateFilePath, replacements) | Sends using an HTML file | Promise\u003cboolean\u003e |\n| sendConfirmationWithRetry(email, subjectTemplate, bodyTemplate, retries, delayMs) | Sends with retries | Promise\u003cboolean\u003e |\n| sendBulkConfirmation(subjectTemplate, bodyTemplate, retries, delayMs) | Sends to all emails | Promise\u003cnumber\u003e |\n| saveWaitlist() | Persists waitlist to storage | Promise\u003cboolean\u003e |\n| findEmailsByPattern(pattern: string) | Finds emails matching a pattern | Promise\u003cstring[]\u003e |\n| countWaitlistByDate(startDate?: Date, endDate?: Date) | Counts emails by date range | Promise\u003cnumber\u003e |\n| close() | Closes database and transporter | Promise\u003cvoid\u003e |\n\n### Events\n\n- `onEmailAdded(email: string)`  \n- `onEmailRemoved(email: string)`  \n- `onEmailSent(email: string, info: SentMessageInfo)`  \n- `onEmailRetry(email: string, attempt: number)`  \n- `onBulkConfirmationComplete({ successCount: number, total: number })`  \n- `onWaitlistSaved(emails: string[])`  \n- `onWaitlistCleared()`  \n- `onValidationError({ email: string, error: string })`  \n- `onDuplicateEmail(email: string)`  \n- `onError({ email: string, action: string, error: unknown })`  \n- `onTransporterReady()`  \n- `onTransporterError(error: Error)`  \n- `onDbConnected()`  \n- `onDbError(error: Error)`  \n- `onSqlConnected()`  \n- `onSqlError(error: Error)`  \n- `onInitialized()`\n\n---\n\n## Common Errors\n\n- **SMTP Connection Refused**: Invalid mailConfig  \n  Fix: Verify host, port, user, pass\n- **Invalid Email**: Format error (e.g., user@)  \n  Fix: Use valid email (e.g., user@example.com)\n- **Duplicate Email**: Email already in waitlist  \n  Fix: Check getWaitlist() or handle onDuplicateEmail\n- **File Not Found**: Wrong templateFilePath  \n  Fix: Ensure file exists and path is correct\n- **Database Failure**: Invalid mongoUri or sqlConfig  \n  Fix: Check DB server and credentials\n\n---\n\n## Contributions\n\n- Fork the repo  \n- Submit pull requests  \n- Report issues on GitHub\n\n---\n\n## License\n\nMIT - Free to use, modify, and distribute with attribution.\n\n---\n\n## Version History\n\n| Version | Date | Description |\n|---------|------|-------------|\n| 1.0.0 | March 3, 2025 | - Stable release with bulk sending\u003cbr\u003e- Indexed MongoDB (Waitlist) and SQL (waitlist) storage\u003cbr\u003e- Advanced queries: findEmailsByPattern, countWaitlistByDate\u003cbr\u003e- Centralized error handling\u003cbr\u003e- Enhanced modularity |\n| 0.1.0 | TBD | - Pre-release: Basic waitlist and email sending\u003cbr\u003e- Local storage only\u003cbr\u003e- Initial event system |\n\n⚠️ Future: UI integration may be considered for later versions.\n\n---","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuanses03%2Fwaitlist-mailer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjuanses03%2Fwaitlist-mailer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuanses03%2Fwaitlist-mailer/lists"}