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

maildrop

v1.0.5

Published

Simple email sending with pre-configured SMTP - no setup required

Readme

maildrop

Simple email sending with pre-configured SMTP - no setup required! 🚀

A lightweight wrapper around Nodemailer that automatically detects SMTP settings based on your email provider. Perfect for when you want Resend-like simplicity but need to use free SMTP services.

Features

  • Zero Configuration - Auto-detects SMTP settings for Gmail, Outlook, Yahoo, and more
  • 🎯 Resend-like API - Familiar interface if you've used Resend
  • 📦 Lightweight - Just a thin wrapper around Nodemailer
  • 🔒 TypeScript - Full TypeScript support
  • 🆓 Free - Uses your existing email account

Installation

npm install maildrop

Quick Start

Method 1: Using Environment Variables (SIMPLEST! 🎯)

import { drop } from 'maildrop';

// Set environment variables:
// [email protected]
// MAILDROP_PASSWORD=your-app-password

const { data, error } = await drop({
  to: '[email protected]',
  subject: 'Hello World',
  html: '<strong>It works!</strong>',
});

if (error) {
  return console.error({ error });
}

console.log({ data });

Method 2: Quick Drop Function (No Class!)

import { quickDrop } from 'maildrop';

const { data, error } = await quickDrop(
  '[email protected]',
  'your-app-password',
  {
    to: '[email protected]',
    subject: 'Hello World',
    html: '<strong>It works!</strong>',
  }
);

Method 3: Class-Based (Original API)

import { MailDrop } from 'maildrop';

const mail = new MailDrop('[email protected]', 'your-app-password');

const { data, error } = await mail.send({
  from: 'Your Name <[email protected]>',
  to: ['[email protected]'],
  subject: 'Hello World',
  html: '<strong>It works!</strong>',
});

Supported Providers

The following email providers are automatically detected:

  • Gmail (gmail.com, googlemail.com)
  • Outlook (outlook.com, hotmail.com, live.com, msn.com)
  • Yahoo (yahoo.com, yahoo.co.uk, ymail.com)
  • Zoho (zoho.com, *.zoho.com)
  • Custom SMTP (see below)

Usage Examples

Simplest: Environment Variables

Create a .env file:

[email protected]
MAILDROP_PASSWORD=your-app-password

Then use:

import { drop } from 'maildrop';

// 'from' is optional - defaults to MAILDROP_EMAIL
const { data, error } = await drop({
  to: '[email protected]',
  subject: 'Hello',
  html: '<p>Hello!</p>',
});

Gmail

Important: Gmail requires an App Password instead of your regular password.

  1. Enable 2-Step Verification on your Google Account
  2. Generate an App Password: Google Account Settings
  3. Use the generated app password (16 characters, no spaces)
import { MailDrop } from 'maildrop';

const mail = new MailDrop('[email protected]', 'your-16-char-app-password');

const { data, error } = await mail.send({
  from: 'Your Name <[email protected]>',
  to: '[email protected]',
  subject: 'Hello from Gmail!',
  html: '<p>This email was sent using Gmail SMTP.</p>',
});

Outlook / Hotmail

const mail = new MailDrop('[email protected]', 'your-password');

const { data, error } = await mail.send({
  from: 'Your Name <[email protected]>',
  to: ['[email protected]'],
  subject: 'Hello from Outlook!',
  html: '<p>This email was sent using Outlook SMTP.</p>',
});

Custom SMTP

For providers not automatically detected, you can provide custom SMTP settings:

const mail = new MailDrop(
  '[email protected]',
  'password',
  {
    host: 'smtp.example.com',
    port: 587,
    secure: false, // true for 465, false for other ports
  }
);

Multiple Recipients

const { data, error } = await mail.send({
  from: '[email protected]',
  to: ['[email protected]', '[email protected]'],
  cc: ['[email protected]'],
  bcc: ['[email protected]'],
  subject: 'Hello',
  html: '<p>Hello everyone!</p>',
});

Text and HTML

const { data, error } = await mail.send({
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Hello',
  text: 'Plain text version',
  html: '<p>HTML version</p>',
});

Verify Connection

Test your SMTP connection before sending:

const mail = new MailDrop('[email protected]', 'your-password');

const isValid = await mail.verify();
if (isValid) {
  console.log('SMTP connection is valid!');
} else {
  console.error('SMTP connection failed. Check your credentials.');
}

API Reference

drop() - Simplest Method! ⭐

Drop an email using environment variables. No credentials needed in code!

drop(options: Omit<SendEmailOptions, 'from'> & { from?: string }): Promise<SendEmailResponse>

Environment Variables Required:

  • MAILDROP_EMAIL - Your email address
  • MAILDROP_PASSWORD - Your email password/app-password

Options:

  • to (string | string[]) - Recipient email address(es) - required
  • subject (string) - Email subject - required
  • html (string, optional) - HTML content
  • text (string, optional) - Plain text content
  • from (string, optional) - Sender email address (defaults to MAILDROP_EMAIL)
  • cc (string | string[], optional) - CC recipients
  • bcc (string | string[], optional) - BCC recipients
  • replyTo (string, optional) - Reply-to address

Example:

import { drop } from 'maildrop';

const { data, error } = await drop({
  to: '[email protected]',
  subject: 'Hello',
  html: '<p>Hello!</p>',
});

quickDrop() - One-Liner Function

Drop an email without class instantiation.

quickDrop(email: string, password: string, options: Omit<SendEmailOptions, 'from'> & { from?: string }): Promise<SendEmailResponse>

Parameters:

  • email - Your email address
  • password - Your email password/app-password
  • options - Email options (same as drop, from defaults to email)

Example:

import { quickDrop } from 'maildrop';

const { data, error } = await quickDrop(
  '[email protected]',
  'app-password',
  {
    to: '[email protected]',
    subject: 'Hello',
    html: '<p>Hello!</p>',
  }
);

MailDrop - Class-Based API

Constructor

new MailDrop(email: string, password: string, customSMTP?: SMTPConfig)
  • email - Your email address
  • password - Your email password or app-specific password
  • customSMTP - Optional custom SMTP configuration

Methods

send(options: SendEmailOptions): Promise<SendEmailResponse>

Send an email.

Options:

  • from (string) - Sender email address
  • to (string | string[]) - Recipient email address(es)
  • subject (string) - Email subject
  • html (string, optional) - HTML content
  • text (string, optional) - Plain text content
  • cc (string | string[], optional) - CC recipients
  • bcc (string | string[], optional) - BCC recipients
  • replyTo (string, optional) - Reply-to address

Returns:

{
  data?: {
    id: string;
    messageId: string;
  };
  error?: {
    message: string;
    code?: string;
  };
}
verify(): Promise<boolean>

Verify SMTP connection. Returns true if connection is valid.

Bulk Email Sending

maildrop supports sending to multiple recipients in a single call. You can use arrays for to, cc, and bcc fields:

const { data, error } = await drop({
  to: ['[email protected]', '[email protected]', '[email protected]'],
  subject: 'Newsletter',
  html: '<p>Hello everyone!</p>',
});

Best Practices for Bulk Sending

For small batches (< 50 emails):

  • Use arrays directly in to, cc, or bcc
  • All recipients will see each other's addresses (use bcc for privacy)

For larger batches (> 50 emails):

  • Use bcc to hide recipient addresses from each other
  • Consider sending in smaller batches with delays to avoid rate limits
  • Use a queue system for production applications
// Good: Use BCC for privacy
const { data, error } = await drop({
  to: '[email protected]', // Your address in 'to'
  bcc: ['[email protected]', '[email protected]', /* ... many more */],
  subject: 'Newsletter',
  html: '<p>Hello!</p>',
});

// Better: Send in batches for large lists
const recipients = [/* large array */];
const batchSize = 50;

for (let i = 0; i < recipients.length; i += batchSize) {
  const batch = recipients.slice(i, i + batchSize);
  await drop({
    bcc: batch,
    subject: 'Newsletter',
    html: '<p>Hello!</p>',
  });
  
  // Small delay to avoid rate limits
  await new Promise(resolve => setTimeout(resolve, 1000));
}

Rate Limits:

  • Gmail: ~500 emails/day for free accounts, ~2000/day for Google Workspace
  • Outlook: ~300 emails/day for free accounts
  • Yahoo: ~500 emails/day

For production bulk email, consider using dedicated email services (SendGrid, Mailgun, etc.) or upgrade to a business email account.

Advanced Custom SMTP Configuration

For custom SMTP servers, you can provide additional configuration options:

const mail = new MailDrop(
  '[email protected]',
  'password',
  {
    host: 'smtp.example.com',
    port: 587,        // 587 for TLS, 465 for SSL
    secure: false,     // true for SSL (port 465), false for TLS (port 587)
  }
);

Common SMTP Ports

  • 587 - TLS (STARTTLS) - Most common, recommended
  • 465 - SSL - Legacy but still widely used
  • 25 - Unencrypted - Not recommended, often blocked
  • 2525 - Alternative TLS port (some providers)

Enterprise SMTP Providers

Many enterprise email providers use custom SMTP settings:

// Example: Custom corporate email
const mail = new MailDrop(
  '[email protected]',
  'password',
  {
    host: 'mail.company.com',  // Your company's mail server
    port: 587,
    secure: false,
  }
);

Note: maildrop uses Nodemailer under the hood, so you can access the full Nodemailer API if needed by accessing the transporter directly (though this requires modifying the source code).

Error Handling

Always check for errors:

const { data, error } = await mail.send({
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Hello',
  html: '<p>Hello</p>',
});

if (error) {
  console.error('Failed to send email:', error.message);
  // Handle error
  return;
}

console.log('Email sent successfully:', data.messageId);

Handling Bulk Send Errors

When sending to multiple recipients, handle errors gracefully:

const recipients = ['[email protected]', '[email protected]', '[email protected]'];
const results = [];

for (const recipient of recipients) {
  const { data, error } = await drop({
    to: recipient,
    subject: 'Hello',
    html: '<p>Hello!</p>',
  });
  
  if (error) {
    console.error(`Failed to send to ${recipient}:`, error.message);
    results.push({ recipient, success: false, error: error.message });
  } else {
    results.push({ recipient, success: true, messageId: data?.messageId });
  }
}

console.log(`Sent ${results.filter(r => r.success).length}/${recipients.length} emails`);

Common Issues

Gmail: "Username and Password not accepted"

  • Make sure you're using an App Password, not your regular Gmail password
  • Enable 2-Step Verification first
  • Generate a new App Password if needed

Outlook: Authentication failed

  • Make sure you're using your full email address as the username
  • Some accounts may require enabling "Less secure app access" (not recommended)
  • Consider using an App Password instead

Connection timeout

  • Check your firewall settings
  • Verify the SMTP port (587 for TLS, 465 for SSL)
  • Some networks block SMTP ports

Rate limiting / Account suspension

  • Free email accounts have daily sending limits
  • Sending too many emails too quickly can trigger spam filters
  • If your account gets suspended, wait 24 hours before trying again
  • For production, consider using a dedicated email service

Production Best Practices

Environment Variables

Always use environment variables for credentials in production:

// ✅ Good: Using environment variables
const { data, error } = await drop({
  to: process.env.ADMIN_EMAIL,
  subject: 'System Alert',
  html: '<p>Alert message</p>',
});

// ❌ Bad: Hardcoded credentials
const { data, error } = await quickDrop(
  '[email protected]',
  'my-password', // Never do this!
  { /* ... */ }
);

Error Handling & Retries

Implement retry logic for production applications:

async function sendWithRetry(options: SendEmailOptions, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    const { data, error } = await drop(options);
    
    if (!error) {
      return { data, error: null };
    }
    
    // Don't retry on authentication errors
    if (error.code === 'EAUTH' || error.message.includes('password')) {
      return { data: null, error };
    }
    
    // Wait before retrying (exponential backoff)
    if (attempt < maxRetries) {
      await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
    }
  }
  
  return { data: null, error: { message: 'Max retries exceeded' } };
}

Queue System for High Volume

For applications sending many emails, use a queue system:

// Example using a simple queue
const emailQueue: Array<SendEmailOptions> = [];

async function processQueue() {
  while (emailQueue.length > 0) {
    const email = emailQueue.shift();
    if (email) {
      const { error } = await drop(email);
      if (error) {
        console.error('Failed to send:', error);
        // Add to retry queue or log for manual review
      }
      // Rate limiting: wait between sends
      await new Promise(resolve => setTimeout(resolve, 100));
    }
  }
}

Monitoring & Logging

Log email sends for debugging and monitoring:

async function sendWithLogging(options: SendEmailOptions) {
  const startTime = Date.now();
  const { data, error } = await drop(options);
  const duration = Date.now() - startTime;
  
  if (error) {
    console.error('[Email] Failed:', {
      to: options.to,
      error: error.message,
      duration,
    });
  } else {
    console.log('[Email] Sent:', {
      to: options.to,
      messageId: data?.messageId,
      duration,
    });
  }
  
  return { data, error };
}

When to Use maildrop vs. Dedicated Services

Use maildrop when:

  • ✅ Sending transactional emails (welcome emails, password resets, notifications)
  • ✅ Low to medium volume (< 1000 emails/day)
  • ✅ Personal projects or small applications
  • ✅ You want to use your existing email account

Consider dedicated services when:

  • ❌ High volume (> 1000 emails/day)
  • ❌ Marketing campaigns or newsletters
  • ❌ Need advanced analytics and tracking
  • ❌ Need guaranteed delivery rates
  • ❌ Enterprise requirements

Popular alternatives: SendGrid, Mailgun, AWS SES, Postmark, Resend

License

ISC

Contributing

Contributions welcome! Feel free to open issues or submit pull requests.