+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Part 207 of 354

๐Ÿ“ง Email Services: Nodemailer Setup

Master email services: nodemailer setup in TypeScript with practical examples, best practices, and real-world applications ๐Ÿš€

๐Ÿš€Intermediate
30 min read

Prerequisites

  • Basic understanding of JavaScript ๐Ÿ“
  • TypeScript installation โšก
  • VS Code or preferred IDE ๐Ÿ’ป

What you'll learn

  • Understand nodemailer fundamentals ๐ŸŽฏ
  • Apply email services in real projects ๐Ÿ—๏ธ
  • Debug common email issues ๐Ÿ›
  • Write type-safe email code โœจ

๐ŸŽฏ Introduction

Welcome to this exciting tutorial on email services with Nodemailer! ๐Ÿ“ง In this guide, weโ€™ll explore how to send emails programmatically using TypeScript and the powerful Nodemailer library.

Youโ€™ll discover how email services can transform your applications - from user notifications ๐Ÿ“ฌ, account verification ๐Ÿ”, to marketing campaigns ๐Ÿ“ˆ. Whether youโ€™re building web applications ๐ŸŒ, server-side APIs ๐Ÿ–ฅ๏ธ, or automated systems ๐Ÿค–, understanding email integration is essential for modern development.

By the end of this tutorial, youโ€™ll feel confident implementing email services in your TypeScript projects! Letโ€™s dive in! ๐ŸŠโ€โ™‚๏ธ

๐Ÿ“š Understanding Email Services

๐Ÿค” What is Nodemailer?

Nodemailer is like having your own personal mail carrier ๐Ÿ“ฎ for your applications. Think of it as a digital postman that can send emails from your code to anyone in the world!

In TypeScript terms, Nodemailer provides a type-safe way to handle email delivery ๐Ÿ“ง. This means you can:

  • โœจ Send professional emails programmatically
  • ๐Ÿš€ Handle attachments and HTML content
  • ๐Ÿ›ก๏ธ Use secure authentication methods
  • ๐Ÿ“Š Track email delivery status

๐Ÿ’ก Why Use Nodemailer?

Hereโ€™s why developers love Nodemailer:

  1. Type Safety ๐Ÿ”’: Full TypeScript support with proper typing
  2. Multiple Providers ๐Ÿ’ป: Works with Gmail, Outlook, SendGrid, and more
  3. Rich Features ๐Ÿ“–: Attachments, HTML emails, templates
  4. Reliability ๐Ÿ”ง: Robust error handling and retry mechanisms

Real-world example: Imagine building an e-commerce site ๐Ÿ›’. With Nodemailer, you can send order confirmations, shipping updates, and promotional emails automatically!

๐Ÿ”ง Basic Syntax and Usage

๐Ÿ“ Installation and Setup

Letโ€™s start by setting up our project:

# ๐Ÿ“ฆ Install dependencies
npm install nodemailer
npm install -D @types/nodemailer

# โšก Or with pnpm
pnpm add nodemailer
pnpm add -D @types/nodemailer

๐ŸŽฏ Basic Configuration

Hereโ€™s your first email service setup:

// ๐Ÿ“ง Basic email service setup
import nodemailer from 'nodemailer';

// ๐Ÿ”ง Email configuration interface
interface EmailConfig {
  host: string;
  port: number;     // ๐Ÿ“ซ Mail server port
  secure: boolean;  // ๐Ÿ”’ Use SSL/TLS
  auth: {
    user: string;   // ๐Ÿ‘ค Your email
    pass: string;   // ๐Ÿ—๏ธ Your password (use app passwords!)
  };
}

// ๐ŸŽจ Creating a transporter
const emailConfig: EmailConfig = {
  host: 'smtp.gmail.com',
  port: 587,
  secure: false, // ๐Ÿ”“ Use STARTTLS
  auth: {
    user: '[email protected]',
    pass: 'your-app-password' // โš ๏ธ Never hardcode this!
  }
};

const transporter = nodemailer.createTransporter(emailConfig);

๐Ÿ’ก Pro Tip: Always use environment variables for sensitive data like passwords!

๐ŸŽฎ Simple Email Example

// ๐Ÿ“ฌ Email message interface
interface EmailMessage {
  from: string;       // ๐Ÿ‘ค Sender
  to: string | string[]; // ๐Ÿ“ฎ Recipients
  subject: string;    // ๐Ÿ“ Email subject
  text?: string;      // ๐Ÿ“„ Plain text
  html?: string;      // ๐ŸŽจ HTML content
  attachments?: any[]; // ๐Ÿ“Ž File attachments
}

// โœ‰๏ธ Send a simple email
async function sendWelcomeEmail(userEmail: string, userName: string): Promise<void> {
  const message: EmailMessage = {
    from: '"Welcome Team ๐Ÿ‘‹" <[email protected]>',
    to: userEmail,
    subject: `Welcome to our app, ${userName}! ๐ŸŽ‰`,
    html: `
      <div style="font-family: Arial, sans-serif; max-width: 600px;">
        <h2>Welcome ${userName}! ๐ŸŽ‰</h2>
        <p>We're excited to have you join our community! ๐Ÿš€</p>
        <p>Get started by exploring these features:</p>
        <ul>
          <li>๐Ÿ“Š Dashboard analytics</li>
          <li>๐Ÿ› ๏ธ Project management tools</li>
          <li>๐Ÿ‘ฅ Team collaboration</li>
        </ul>
        <p>Happy coding! ๐Ÿ’ปโœจ</p>
      </div>
    `
  };

  try {
    const info = await transporter.sendMail(message);
    console.log('๐Ÿ“ง Email sent successfully!', info.messageId);
  } catch (error) {
    console.error('โŒ Failed to send email:', error);
    throw error;
  }
}

๐Ÿ’ก Practical Examples

๐Ÿ›’ Example 1: E-commerce Order Confirmation

Letโ€™s build a real e-commerce email system:

// ๐Ÿ›๏ธ Order and product interfaces
interface Product {
  id: string;
  name: string;
  price: number;
  quantity: number;
  emoji: string;
}

interface Order {
  id: string;
  customerName: string;
  customerEmail: string;
  products: Product[];
  totalAmount: number;
  orderDate: Date;
  shippingAddress: string;
}

// ๐Ÿ“ง E-commerce email service
class ECommerceEmailService {
  private transporter: nodemailer.Transporter;

  constructor(config: EmailConfig) {
    this.transporter = nodemailer.createTransporter(config);
  }

  // ๐Ÿ“ฆ Send order confirmation
  async sendOrderConfirmation(order: Order): Promise<void> {
    const productsHtml = order.products
      .map(product => `
        <tr>
          <td>${product.emoji} ${product.name}</td>
          <td>${product.quantity}</td>
          <td>$${product.price.toFixed(2)}</td>
          <td>$${(product.price * product.quantity).toFixed(2)}</td>
        </tr>
      `).join('');

    const emailHtml = `
      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
        <h2>๐ŸŽ‰ Order Confirmation #${order.id}</h2>
        <p>Hi ${order.customerName},</p>
        <p>Thanks for your order! Here are the details:</p>
        
        <table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
          <thead>
            <tr style="background-color: #f5f5f5;">
              <th style="padding: 10px; border: 1px solid #ddd;">Product</th>
              <th style="padding: 10px; border: 1px solid #ddd;">Qty</th>
              <th style="padding: 10px; border: 1px solid #ddd;">Price</th>
              <th style="padding: 10px; border: 1px solid #ddd;">Total</th>
            </tr>
          </thead>
          <tbody>
            ${productsHtml}
          </tbody>
        </table>
        
        <div style="background-color: #f9f9f9; padding: 15px; margin: 20px 0;">
          <h3>๐Ÿ“‹ Order Summary</h3>
          <p><strong>Total Amount: $${order.totalAmount.toFixed(2)}</strong></p>
          <p><strong>Order Date:</strong> ${order.orderDate.toLocaleDateString()}</p>
          <p><strong>Shipping Address:</strong> ${order.shippingAddress}</p>
        </div>
        
        <p>We'll send you a shipping confirmation once your order is on its way! ๐Ÿšš</p>
        <p>Happy shopping! ๐Ÿ›’โœจ</p>
      </div>
    `;

    await this.transporter.sendMail({
      from: '"ShopMaster ๐Ÿ›’" <[email protected]>',
      to: order.customerEmail,
      subject: `Order Confirmation #${order.id} ๐Ÿ“ฆ`,
      html: emailHtml
    });

    console.log(`โœ… Order confirmation sent to ${order.customerEmail}`);
  }

  // ๐Ÿšš Send shipping notification
  async sendShippingNotification(order: Order, trackingNumber: string): Promise<void> {
    const emailHtml = `
      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
        <h2>๐Ÿšš Your Order is on the Way!</h2>
        <p>Hi ${order.customerName},</p>
        <p>Great news! Your order #${order.id} has been shipped and is on its way to you! ๐Ÿ“ฆ</p>
        
        <div style="background-color: #e8f5e8; padding: 20px; margin: 20px 0; border-radius: 8px;">
          <h3>๐Ÿ“ Tracking Information</h3>
          <p><strong>Tracking Number:</strong> <code>${trackingNumber}</code></p>
          <p><strong>Estimated Delivery:</strong> 3-5 business days ๐Ÿ“…</p>
        </div>
        
        <p>You can track your package using the tracking number above. ๐Ÿ”</p>
        <p>Thanks for shopping with us! ๐Ÿ™</p>
      </div>
    `;

    await this.transporter.sendMail({
      from: '"ShipMaster ๐Ÿšš" <[email protected]>',
      to: order.customerEmail,
      subject: `๐Ÿ“ฆ Your order #${order.id} is shipped!`,
      html: emailHtml
    });

    console.log(`๐Ÿšš Shipping notification sent to ${order.customerEmail}`);
  }
}

๐ŸŽฎ Example 2: User Authentication System

Letโ€™s create an authentication email service:

// ๐Ÿ” Authentication email service
class AuthEmailService {
  private transporter: nodemailer.Transporter;
  private baseUrl: string;

  constructor(config: EmailConfig, baseUrl: string) {
    this.transporter = nodemailer.createTransporter(config);
    this.baseUrl = baseUrl;
  }

  // โœ‰๏ธ Send verification email
  async sendVerificationEmail(email: string, token: string): Promise<void> {
    const verificationUrl = `${this.baseUrl}/verify-email?token=${token}`;
    
    const emailHtml = `
      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
        <h2>๐Ÿ” Verify Your Email Address</h2>
        <p>Welcome! Please click the button below to verify your email address:</p>
        
        <div style="text-align: center; margin: 30px 0;">
          <a href="${verificationUrl}" 
             style="background-color: #007bff; color: white; padding: 12px 24px; 
                    text-decoration: none; border-radius: 6px; display: inline-block;">
            โœ… Verify Email Address
          </a>
        </div>
        
        <p>Or copy and paste this link into your browser:</p>
        <p style="word-break: break-all; color: #666;">
          ${verificationUrl}
        </p>
        
        <div style="background-color: #fff3cd; padding: 15px; margin: 20px 0; border-radius: 6px;">
          <p><strong>โš ๏ธ Important:</strong> This link will expire in 24 hours for security.</p>
        </div>
        
        <p>If you didn't create this account, please ignore this email. ๐Ÿคทโ€โ™‚๏ธ</p>
      </div>
    `;

    await this.transporter.sendMail({
      from: '"SecureApp ๐Ÿ”’" <[email protected]>',
      to: email,
      subject: '๐Ÿ” Please verify your email address',
      html: emailHtml
    });

    console.log(`๐Ÿ“ง Verification email sent to ${email}`);
  }

  // ๐Ÿ”„ Send password reset email
  async sendPasswordResetEmail(email: string, resetToken: string): Promise<void> {
    const resetUrl = `${this.baseUrl}/reset-password?token=${resetToken}`;
    
    const emailHtml = `
      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
        <h2>๐Ÿ”‘ Password Reset Request</h2>
        <p>We received a request to reset your password. Click the button below to create a new password:</p>
        
        <div style="text-align: center; margin: 30px 0;">
          <a href="${resetUrl}" 
             style="background-color: #dc3545; color: white; padding: 12px 24px; 
                    text-decoration: none; border-radius: 6px; display: inline-block;">
            ๐Ÿ”‘ Reset Password
          </a>
        </div>
        
        <div style="background-color: #f8d7da; padding: 15px; margin: 20px 0; border-radius: 6px;">
          <p><strong>๐Ÿšจ Security Notice:</strong></p>
          <ul>
            <li>This link expires in 1 hour โฐ</li>
            <li>Only use this if you requested it ๐Ÿ›ก๏ธ</li>
            <li>Never share this link with anyone ๐Ÿคซ</li>
          </ul>
        </div>
        
        <p>If you didn't request this, please ignore this email and your password will remain unchanged. ๐Ÿ”’</p>
      </div>
    `;

    await this.transporter.sendMail({
      from: '"SecureApp ๐Ÿ”’" <[email protected]>',
      to: email,
      subject: '๐Ÿ”‘ Password Reset Request',
      html: emailHtml
    });

    console.log(`๐Ÿ”‘ Password reset email sent to ${email}`);
  }
}

๐Ÿš€ Advanced Concepts

๐Ÿง™โ€โ™‚๏ธ Advanced Topic 1: Email Templates with Handlebars

When youโ€™re ready to level up, try template engines:

// ๐ŸŽจ Advanced email template system
import handlebars from 'handlebars';
import fs from 'fs/promises';
import path from 'path';

class AdvancedEmailService {
  private transporter: nodemailer.Transporter;
  private templatesPath: string;

  constructor(config: EmailConfig, templatesPath: string) {
    this.transporter = nodemailer.createTransporter(config);
    this.templatesPath = templatesPath;
  }

  // ๐Ÿ“„ Load and compile template
  private async loadTemplate(templateName: string): Promise<HandlebarsTemplateDelegate> {
    const templatePath = path.join(this.templatesPath, `${templateName}.hbs`);
    const templateContent = await fs.readFile(templatePath, 'utf-8');
    return handlebars.compile(templateContent);
  }

  // ๐Ÿ“ง Send templated email
  async sendTemplatedEmail<T = any>(
    templateName: string,
    to: string,
    subject: string,
    data: T
  ): Promise<void> {
    try {
      const template = await this.loadTemplate(templateName);
      const html = template(data);

      await this.transporter.sendMail({
        from: '"TemplateApp ๐ŸŽจ" <[email protected]>',
        to,
        subject,
        html
      });

      console.log(`โœจ Templated email sent: ${templateName} to ${to}`);
    } catch (error) {
      console.error('โŒ Template email failed:', error);
      throw error;
    }
  }
}

// ๐ŸŽฏ Usage with type safety
interface WelcomeEmailData {
  userName: string;
  appName: string;
  features: string[];
  ctaUrl: string;
}

const emailService = new AdvancedEmailService(emailConfig, './templates');

// ๐Ÿ“ง Send welcome email with template
await emailService.sendTemplatedEmail<WelcomeEmailData>(
  'welcome', 
  '[email protected]',
  'Welcome to our amazing app! ๐ŸŽ‰',
  {
    userName: 'Sarah',
    appName: 'CodeMaster',
    features: ['๐Ÿ’ป Code Editor', '๐Ÿ” Live Preview', '๐Ÿค Collaboration'],
    ctaUrl: 'https://codemaster.com/dashboard'
  }
);

๐Ÿ—๏ธ Advanced Topic 2: Email Queue System

For the brave developers, hereโ€™s a scalable email queue:

// ๐Ÿ“ฌ Email queue with Bull (Redis-based)
import Queue from 'bull';

interface EmailJob {
  type: 'welcome' | 'verification' | 'reset-password' | 'order-confirmation';
  to: string;
  data: any;
}

class EmailQueueService {
  private emailQueue: Queue.Queue<EmailJob>;
  private emailService: AdvancedEmailService;

  constructor(redisConfig: any, emailService: AdvancedEmailService) {
    this.emailQueue = new Queue('email processing', redisConfig);
    this.emailService = emailService;
    this.setupWorkers();
  }

  // ๐Ÿ”„ Setup queue workers
  private setupWorkers(): void {
    this.emailQueue.process('send-email', 5, async (job) => {
      const { type, to, data } = job.data;
      
      console.log(`๐Ÿ“ง Processing ${type} email for ${to}`);
      
      switch (type) {
        case 'welcome':
          await this.emailService.sendTemplatedEmail('welcome', to, 'Welcome! ๐ŸŽ‰', data);
          break;
        case 'verification':
          await this.emailService.sendTemplatedEmail('verification', to, 'Verify Email ๐Ÿ”', data);
          break;
        // ... more cases
      }
      
      console.log(`โœ… Email sent: ${type} to ${to}`);
    });

    // ๐Ÿ“Š Queue event listeners
    this.emailQueue.on('completed', (job, result) => {
      console.log(`๐ŸŽ‰ Job ${job.id} completed`);
    });

    this.emailQueue.on('failed', (job, err) => {
      console.log(`โŒ Job ${job.id} failed:`, err.message);
    });
  }

  // โž• Add email to queue
  async queueEmail(emailJob: EmailJob): Promise<void> {
    await this.emailQueue.add('send-email', emailJob, {
      attempts: 3,
      backoff: 'exponential',
      delay: 5000
    });
    
    console.log(`๐Ÿ“ฌ Email queued: ${emailJob.type} for ${emailJob.to}`);
  }
}

โš ๏ธ Common Pitfalls and Solutions

๐Ÿ˜ฑ Pitfall 1: Hardcoded Credentials

// โŒ Wrong way - security nightmare!
const transporter = nodemailer.createTransporter({
  service: 'gmail',
  auth: {
    user: '[email protected]',     // ๐Ÿ˜ฐ Exposed!
    pass: 'mypassword123'          // ๐Ÿ’ฅ Very dangerous!
  }
});

// โœ… Correct way - use environment variables!
const transporter = nodemailer.createTransporter({
  service: 'gmail',
  auth: {
    user: process.env.EMAIL_USER,    // ๐Ÿ›ก๏ธ Secure!
    pass: process.env.EMAIL_PASS     // ๐Ÿ”’ App-specific password
  }
});

// ๐Ÿ’ก Add to your .env file:
// [email protected]
// EMAIL_PASS=your-app-specific-password

๐Ÿคฏ Pitfall 2: Not Handling Async Errors

// โŒ Dangerous - unhandled promise rejection!
function sendEmail() {
  transporter.sendMail(message); // ๐Ÿ’ฅ No error handling!
}

// โœ… Safe - proper error handling!
async function sendEmail(): Promise<void> {
  try {
    const info = await transporter.sendMail(message);
    console.log('โœ… Email sent:', info.messageId);
  } catch (error) {
    console.error('โŒ Email failed:', error);
    // ๐Ÿšจ Maybe add to retry queue or alert admins
    throw error;
  }
}

๐Ÿšซ Pitfall 3: HTML Injection Vulnerability

// โŒ Vulnerable to XSS attacks!
function sendWelcomeEmail(userName: string): void {
  const html = `<h1>Welcome ${userName}!</h1>`; // ๐Ÿ’ฅ No sanitization!
}

// โœ… Safe - sanitize user input!
import DOMPurify from 'isomorphic-dompurify';

function sendWelcomeEmail(userName: string): void {
  const sanitizedName = DOMPurify.sanitize(userName);
  const html = `<h1>Welcome ${sanitizedName}!</h1>`; // ๐Ÿ›ก๏ธ Safe now!
}

๐Ÿ› ๏ธ Best Practices

  1. ๐Ÿ” Security First: Always use environment variables for credentials
  2. ๐Ÿ“ Template System: Use templates for complex emails
  3. ๐Ÿš€ Queue System: Use queues for high-volume email sending
  4. ๐Ÿ›ก๏ธ Input Sanitization: Never trust user input in email content
  5. ๐Ÿ“Š Error Handling: Always handle email failures gracefully
  6. โšก Rate Limiting: Respect email provider rate limits
  7. ๐Ÿ“ฑ Mobile-Friendly: Design responsive email templates
  8. ๐Ÿงช Testing: Test emails with different providers

๐Ÿงช Hands-On Exercise

๐ŸŽฏ Challenge: Build a Newsletter System

Create a complete newsletter system with subscription management:

๐Ÿ“‹ Requirements:

  • โœ… Subscribe/unsubscribe functionality
  • ๐Ÿ“ง Welcome email for new subscribers
  • ๐Ÿ“ฐ Send newsletter to all subscribers
  • ๐Ÿ“Š Track email delivery status
  • ๐ŸŽจ Use HTML templates
  • ๐Ÿ”„ Queue system for bulk emails

๐Ÿš€ Bonus Points:

  • Add email preferences (daily/weekly)
  • Implement A/B testing for subject lines
  • Add click tracking
  • Create an admin dashboard

๐Ÿ’ก Solution

๐Ÿ” Click to see solution
// ๐Ÿ“ฐ Complete newsletter system
interface Subscriber {
  id: string;
  email: string;
  name: string;
  subscribedAt: Date;
  preferences: {
    frequency: 'daily' | 'weekly' | 'monthly';
    topics: string[];
  };
  isActive: boolean;
}

interface Newsletter {
  id: string;
  subject: string;
  content: string;
  scheduledFor: Date;
  status: 'draft' | 'scheduled' | 'sent';
}

class NewsletterService {
  private transporter: nodemailer.Transporter;
  private subscribers: Map<string, Subscriber> = new Map();
  private newsletters: Newsletter[] = [];

  constructor(config: EmailConfig) {
    this.transporter = nodemailer.createTransporter(config);
  }

  // โž• Subscribe user
  async subscribe(email: string, name: string): Promise<void> {
    const subscriber: Subscriber = {
      id: Date.now().toString(),
      email,
      name,
      subscribedAt: new Date(),
      preferences: {
        frequency: 'weekly',
        topics: ['tech', 'tutorials']
      },
      isActive: true
    };

    this.subscribers.set(subscriber.id, subscriber);
    
    // ๐ŸŽ‰ Send welcome email
    await this.sendWelcomeEmail(subscriber);
    console.log(`โœ… New subscriber: ${email}`);
  }

  // โœ‰๏ธ Send welcome email
  private async sendWelcomeEmail(subscriber: Subscriber): Promise<void> {
    const welcomeHtml = `
      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
        <h2>๐ŸŽ‰ Welcome to Our Newsletter, ${subscriber.name}!</h2>
        <p>Thanks for subscribing! You'll receive our ${subscriber.preferences.frequency} updates.</p>
        
        <div style="background-color: #f0f8ff; padding: 20px; margin: 20px 0; border-radius: 8px;">
          <h3>๐Ÿ“š What to Expect:</h3>
          <ul>
            <li>๐Ÿ”ฅ Latest tech trends and tutorials</li>
            <li>๐Ÿ’ก Programming tips and tricks</li>
            <li>๐Ÿš€ Project inspiration and ideas</li>
            <li>๐Ÿ“ˆ Industry insights and analysis</li>
          </ul>
        </div>
        
        <p>You can update your preferences or unsubscribe anytime. ๐Ÿ› ๏ธ</p>
        <p>Happy learning! ๐Ÿ“–โœจ</p>
      </div>
    `;

    await this.transporter.sendMail({
      from: '"Newsletter Team ๐Ÿ“ฐ" <[email protected]>',
      to: subscriber.email,
      subject: `Welcome to our community, ${subscriber.name}! ๐ŸŽ‰`,
      html: welcomeHtml
    });
  }

  // ๐Ÿ“ง Send newsletter to all subscribers
  async sendNewsletter(newsletter: Newsletter): Promise<void> {
    const activeSubscribers = Array.from(this.subscribers.values())
      .filter(sub => sub.isActive);

    console.log(`๐Ÿ“ฌ Sending newsletter to ${activeSubscribers.length} subscribers`);

    // ๐Ÿ”„ Send in batches to avoid rate limits
    const batchSize = 10;
    for (let i = 0; i < activeSubscribers.length; i += batchSize) {
      const batch = activeSubscribers.slice(i, i + batchSize);
      
      await Promise.all(batch.map(subscriber => 
        this.sendNewsletterToSubscriber(newsletter, subscriber)
      ));
      
      // โฑ๏ธ Brief pause between batches
      await new Promise(resolve => setTimeout(resolve, 1000));
    }

    newsletter.status = 'sent';
    console.log(`โœ… Newsletter sent to all ${activeSubscribers.length} subscribers`);
  }

  // ๐Ÿ“ฌ Send newsletter to individual subscriber
  private async sendNewsletterToSubscriber(
    newsletter: Newsletter, 
    subscriber: Subscriber
  ): Promise<void> {
    const unsubscribeUrl = `https://yourapp.com/unsubscribe?id=${subscriber.id}`;
    
    const emailHtml = `
      <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
        <div style="text-align: center; padding: 20px; background-color: #f8f9fa;">
          <h1>๐Ÿ“ฐ Weekly Newsletter</h1>
        </div>
        
        <div style="padding: 20px;">
          <p>Hi ${subscriber.name}! ๐Ÿ‘‹</p>
          ${newsletter.content}
        </div>
        
        <div style="padding: 20px; background-color: #f8f9fa; text-align: center; margin-top: 30px;">
          <p style="color: #666; font-size: 12px;">
            ๐Ÿ“ฌ You're receiving this because you subscribed to our newsletter.<br>
            <a href="${unsubscribeUrl}" style="color: #007bff;">Unsubscribe</a> | 
            <a href="https://yourapp.com/preferences?id=${subscriber.id}" style="color: #007bff;">Update Preferences</a>
          </p>
        </div>
      </div>
    `;

    try {
      await this.transporter.sendMail({
        from: '"Weekly Newsletter ๐Ÿ“ฐ" <[email protected]>',
        to: subscriber.email,
        subject: newsletter.subject,
        html: emailHtml
      });
      
      console.log(`๐Ÿ“ง Newsletter sent to ${subscriber.email}`);
    } catch (error) {
      console.error(`โŒ Failed to send newsletter to ${subscriber.email}:`, error);
    }
  }

  // ๐Ÿ“Š Get subscriber statistics
  getStats(): void {
    const total = this.subscribers.size;
    const active = Array.from(this.subscribers.values()).filter(s => s.isActive).length;
    
    console.log('๐Ÿ“Š Newsletter Stats:');
    console.log(`  ๐Ÿ“ Total Subscribers: ${total}`);
    console.log(`  โœ… Active Subscribers: ${active}`);
    console.log(`  ๐Ÿ“ฐ Newsletters Sent: ${this.newsletters.filter(n => n.status === 'sent').length}`);
  }
}

// ๐ŸŽฎ Test the newsletter system!
const newsletterService = new NewsletterService(emailConfig);

// Add some subscribers
await newsletterService.subscribe('[email protected]', 'Alice');
await newsletterService.subscribe('[email protected]', 'Bob');

// Create and send newsletter
const newsletter: Newsletter = {
  id: '1',
  subject: '๐Ÿš€ This Week in Tech: AI Breakthroughs & More!',
  content: `
    <h2>๐Ÿ”ฅ Hot Topics This Week</h2>
    <ul>
      <li>๐Ÿค– AI advances in code generation</li>
      <li>๐Ÿ“ฑ New mobile development frameworks</li>
      <li>๐Ÿ”’ Latest in cybersecurity</li>
    </ul>
    <p>Keep coding and stay awesome! ๐Ÿ’ช</p>
  `,
  scheduledFor: new Date(),
  status: 'draft'
};

await newsletterService.sendNewsletter(newsletter);

๐ŸŽ“ Key Takeaways

Youโ€™ve learned so much! Hereโ€™s what you can now do:

  • โœ… Set up Nodemailer with TypeScript and proper configuration ๐Ÿ’ช
  • โœ… Create email templates that look professional and engaging ๐Ÿ›ก๏ธ
  • โœ… Handle authentication and security best practices ๐ŸŽฏ
  • โœ… Build scalable systems with queues and error handling ๐Ÿ›
  • โœ… Avoid common pitfalls that cause security vulnerabilities ๐Ÿš€

Remember: Email services are powerful tools that can significantly enhance user engagement. Use them wisely and always prioritize user privacy and security! ๐Ÿค

๐Ÿค Next Steps

Congratulations! ๐ŸŽ‰ Youโ€™ve mastered email services with Nodemailer!

Hereโ€™s what to do next:

  1. ๐Ÿ’ป Practice with the newsletter system exercise
  2. ๐Ÿ—๏ธ Build a real project with email notifications
  3. ๐Ÿ“š Explore advanced topics like email analytics and A/B testing
  4. ๐ŸŒŸ Learn about email marketing best practices and deliverability

Your next tutorial: Message Queues: RabbitMQ and Kafka - Learn how to build scalable message-driven architectures! ๐Ÿš€

Remember: Every email expert was once a beginner. Keep coding, keep learning, and most importantly, have fun building amazing email experiences! ๐Ÿš€


Happy coding! ๐ŸŽ‰๐Ÿš€โœจ