Skip to main content

Overview

Nodemailer is a flexible SMTP client that allows you to send emails through any SMTP server. Use Nodemailer when you:
  • Have an existing SMTP server
  • Use a provider not natively supported (Gmail, SendGrid SMTP, Amazon SES, etc.)
  • Need full control over email transport
  • Want to use your company’s email infrastructure
  • Need to send emails through custom mail servers
Nodemailer is the third provider ShipFree checks during auto-discovery. It will be used if Resend and Postmark aren’t configured.

Prerequisites

  1. Access to an SMTP server
  2. SMTP credentials (host, port, username, password)

Setup Instructions

Step 1: Gather SMTP Credentials

You’ll need the following from your email provider:
  • SMTP Host - Server address (e.g., smtp.gmail.com)
  • SMTP Port - Usually 587 (STARTTLS) or 465 (TLS/SSL)
  • Username - Your email address or SMTP username
  • Password - Your email password or app-specific password
  • Secure - true for port 465, false for port 587
For Gmail and other providers with 2FA, you’ll need an app-specific password, not your regular account password.

Step 2: Configure Environment Variables

Add these to your .env file:
# Required
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your-email@example.com
SMTP_PASS=your-password-or-app-password

# Optional - "true" for TLS/SSL (port 465), "false" for STARTTLS (port 587)
SMTP_SECURE=false

# Optional - explicitly set Nodemailer as provider
EMAIL_PROVIDER=nodemailer

# Email defaults
DEFAULT_FROM_EMAIL=noreply@yourdomain.com
DEFAULT_FROM_NAME=Your App Name

Step 3: Install Nodemailer

Nodemailer is already included in ShipFree:
// package.json (already installed)
"nodemailer": "^7.0.12",
"@types/nodemailer": "^7.0.4"
If you need to reinstall:
bun add nodemailer
bun add -D @types/nodemailer

Step 4: Test Your Configuration

import { sendEmail, getActiveProviderName } from '@/lib/messaging/email';

// Verify Nodemailer is active
console.log('Active provider:', getActiveProviderName()); // Should output: 'nodemailer'

// Send test email
const result = await sendEmail({
  to: 'test@example.com',
  subject: 'Test from ShipFree via Nodemailer',
  html: '<h1>Success!</h1><p>SMTP is configured correctly.</p>',
});

if (result.success) {
  console.log('Email sent via SMTP!', result.data);
} else {
  console.error('Failed:', result.message);
}

Common SMTP Providers

Setup:
  1. Enable 2-factor authentication on your Google account
  2. Go to Google Account → Security → App passwords
  3. Create a new app password for “Mail”
  4. Use the generated password (not your account password)
Configuration:
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-specific-password
SMTP_SECURE=false
Gmail has a sending limit of 500 emails/day for free accounts and 2,000/day for Google Workspace.
Setup:
  1. Sign up for Amazon SES
  2. Verify your domain or email address
  3. Create SMTP credentials in the SES console
  4. Note your SMTP endpoint (region-specific)
Configuration:
SMTP_HOST=email-smtp.us-east-1.amazonaws.com
SMTP_PORT=587
SMTP_USER=your-ses-smtp-username
SMTP_PASS=your-ses-smtp-password
SMTP_SECURE=false
SES starts in sandbox mode. Request production access to send to any email address.
Setup:
  1. Create a SendGrid account
  2. Go to Settings → API Keys
  3. Create an API key with “Mail Send” permissions
  4. Use “apikey” as username and the API key as password
Configuration:
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASS=your-sendgrid-api-key
SMTP_SECURE=false
Setup:
  1. Ensure SMTP authentication is enabled for your account
  2. Use your Microsoft 365 email and password
  3. May require app password if 2FA is enabled
Configuration:
SMTP_HOST=smtp.office365.com
SMTP_PORT=587
SMTP_USER=your-email@company.com
SMTP_PASS=your-password
SMTP_SECURE=false
Setup:
  1. Create a Mailgun account
  2. Verify your domain
  3. Get SMTP credentials from Mailgun dashboard
Configuration:
SMTP_HOST=smtp.mailgun.org
SMTP_PORT=587
SMTP_USER=postmaster@yourdomain.com
SMTP_PASS=your-mailgun-password
SMTP_SECURE=false
Configuration:
SMTP_HOST=mail.yourdomain.com
SMTP_PORT=587  # or 465 for SSL
SMTP_USER=smtp-username
SMTP_PASS=smtp-password
SMTP_SECURE=false  # or true for port 465
Contact your hosting provider or IT department for SMTP server details.

Features

Email Attachments

Nodemailer has excellent attachment support:
import { sendEmail } from '@/lib/messaging/email';
import { readFileSync } from 'fs';

await sendEmail({
  to: 'user@example.com',
  subject: 'Invoice #1234',
  html: '<p>Please find your invoice attached.</p>',
  attachments: [
    {
      filename: 'invoice.pdf',
      content: readFileSync('./invoice.pdf'),
      contentType: 'application/pdf',
    },
    {
      filename: 'logo.png',
      content: readFileSync('./logo.png'),
      contentType: 'image/png',
      disposition: 'inline', // Embed in email
    },
  ],
});

Custom Headers

Full control over email headers:
await sendEmail({
  to: 'user@example.com',
  subject: 'Newsletter',
  html: '<p>Monthly update</p>',
  emailType: 'marketing',
  includeUnsubscribe: true,
  unsubscribeInfo: {
    baseUrl: 'https://yourdomain.com',
    token: 'user-token',
    writerId: 'newsletter',
  },
});

Reply-To Address

await sendEmail({
  to: 'customer@example.com',
  subject: 'Support Request',
  html: '<p>Your ticket has been created.</p>',
  replyTo: 'support@yourdomain.com',
});

Plain Text Alternative

await sendEmail({
  to: 'user@example.com',
  subject: 'Welcome',
  html: '<h1>Welcome!</h1><p>Thanks for joining.</p>',
  text: 'Welcome!\n\nThanks for joining.',
});

Batch Email Sending

Nodemailer sends batch emails sequentially:
import { sendBatchEmails } from '@/lib/messaging/email';

await sendBatchEmails({
  emails: [
    { to: 'user1@example.com', subject: 'Hi', html: '<p>Hello</p>' },
    { to: 'user2@example.com', subject: 'Hi', html: '<p>Hello</p>' },
  ],
});
While functional, batch sending via SMTP is slower than providers with native batch APIs (like Resend or Postmark).

Environment Variables Reference

VariableRequiredDescriptionExample
SMTP_HOSTYesSMTP server hostnamesmtp.gmail.com
SMTP_PORTYesSMTP server port587 or 465
SMTP_USERYesSMTP username/emailuser@example.com
SMTP_PASSYesSMTP passwordyour-password
SMTP_SECURENoUse TLS/SSL (true for 465, false for 587)false
EMAIL_PROVIDERNoForce Nodemailer as providernodemailer
DEFAULT_FROM_EMAILNoDefault sender emailnoreply@yourdomain.com
DEFAULT_FROM_NAMENoDefault sender nameYour App Name

TLS vs. STARTTLS

Understanding SMTP security:
Most common and recommended
SMTP_PORT=587
SMTP_SECURE=false
  • Connection starts unencrypted
  • Upgrades to TLS via STARTTLS command
  • Widely supported
  • Recommended by most providers

Development vs. Production

Development Setup

For development, consider using:
  1. Log Provider (easiest):
    EMAIL_PROVIDER=log
    
  2. Ethereal Email (test SMTP service):
    // Create test account at https://ethereal.email
    SMTP_HOST=smtp.ethereal.email
    SMTP_PORT=587
    SMTP_USER=your-ethereal-email
    SMTP_PASS=your-ethereal-password
    SMTP_SECURE=false
    
    Emails are caught, not sent - view them at ethereal.email
  3. Gmail (for quick testing):
    SMTP_HOST=smtp.gmail.com
    SMTP_PORT=587
    SMTP_USER=your-gmail@gmail.com
    SMTP_PASS=your-app-password
    SMTP_SECURE=false
    

Production Setup

For production, use a reliable SMTP provider:
# .env.production
SMTP_HOST=smtp.production-provider.com
SMTP_PORT=587
SMTP_USER=production-user
SMTP_PASS=production-password
SMTP_SECURE=false
DEFAULT_FROM_EMAIL=noreply@yourdomain.com
DEFAULT_FROM_NAME=Your App Name

Troubleshooting

Missing or incomplete SMTP configuration.Solution:
  1. Verify all required env vars are set: SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS
  2. Check for typos in variable names
  3. Restart your application
Incorrect SMTP credentials.Solution:
  1. Verify SMTP_USER and SMTP_PASS are correct
  2. For Gmail/Google: Use app-specific password, not account password
  3. Check if 2FA requires app password
  4. Verify account hasn’t been locked
Cannot connect to SMTP server.Solution:
  1. Verify SMTP_HOST is correct
  2. Check SMTP_PORT (587 or 465)
  3. Ensure firewall allows SMTP connections
  4. Try alternative port if blocked
  5. Check if your ISP blocks SMTP
SSL/TLS certificate issue.Solution: For development only, you can bypass (not recommended for production):
// In nodemailer.ts, add to transporter config:
tls: {
  rejectUnauthorized: false
}
For production, fix the certificate issue on your SMTP server.
Common deliverability issues:
  1. Set up SPF record: Add SMTP server to domain’s SPF
  2. Configure DKIM: Set up DKIM signing
  3. Add DMARC policy: Configure DMARC for your domain
  4. Use authenticated domain: Send from verified domain
  5. Warm up IP: Gradually increase sending volume
  6. Avoid spam triggers: Check email content for spam words
SMTP is inherently slower than API-based providers.Improvements:
  1. Use connection pooling (Nodemailer does this automatically)
  2. Switch to API-based provider (Resend, Postmark) for batches
  3. Use background jobs for large sends
  4. Reduce batch size

Code Reference

The Nodemailer provider implementation:
src/lib/messaging/email/providers/nodemailer.ts
Key functions:
  • createNodemailerProvider() - Initialize provider (line 130)
  • getTransporter() - Create SMTP transport (line 37)
  • send() - Send single email (line 67)
  • sendBatch() - Send batch emails (line 96)

When to Use Nodemailer

Nodemailer is ideal when you:
Have existing SMTP infrastructure - Company email server, self-hosted solution
Need maximum flexibility - Full control over transport and configuration
Use unsupported provider - Provider doesn’t have a native ShipFree integration
Require offline capability - Local SMTP server for air-gapped systems
Consider alternatives if you:
  • Need high-volume batch sending (use Resend/Postmark)
  • Want simpler setup (use Resend/Postmark/Plunk)
  • Need maximum deliverability (use Postmark)
  • Want detailed analytics (use Resend/Postmark)

Additional Resources

Nodemailer Documentation

Official Nodemailer docs and guides

SMTP Guide

SMTP configuration reference

Ethereal Email

Test SMTP service for development

Email Testing

Testing strategies with Nodemailer

Next Steps

1

Set up SPF/DKIM

Configure DNS records for better email deliverability
2

Test with Ethereal

Use Ethereal Email to test without sending real emails
3

Monitor sending

Implement logging to track email delivery and failures