maildrop
v1.0.5
Published
Simple email sending with pre-configured SMTP - no setup required
Maintainers
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 maildropQuick 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-passwordThen 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.
- Enable 2-Step Verification on your Google Account
- Generate an App Password: Google Account Settings
- 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 addressMAILDROP_PASSWORD- Your email password/app-password
Options:
to(string | string[]) - Recipient email address(es) - requiredsubject(string) - Email subject - requiredhtml(string, optional) - HTML contenttext(string, optional) - Plain text contentfrom(string, optional) - Sender email address (defaults toMAILDROP_EMAIL)cc(string | string[], optional) - CC recipientsbcc(string | string[], optional) - BCC recipientsreplyTo(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 addresspassword- Your email password/app-passwordoptions- Email options (same asdrop,fromdefaults toemail)
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 addresspassword- Your email password or app-specific passwordcustomSMTP- Optional custom SMTP configuration
Methods
send(options: SendEmailOptions): Promise<SendEmailResponse>
Send an email.
Options:
from(string) - Sender email addressto(string | string[]) - Recipient email address(es)subject(string) - Email subjecthtml(string, optional) - HTML contenttext(string, optional) - Plain text contentcc(string | string[], optional) - CC recipientsbcc(string | string[], optional) - BCC recipientsreplyTo(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, orbcc - All recipients will see each other's addresses (use
bccfor privacy)
For larger batches (> 50 emails):
- Use
bccto 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.
