Profiles·Public

nodemailer

semver>=7.0.11 <10.0.0postconditions12functions4last verified2026-06-23coverage score100%

Postconditions: what we check

  • sendMail · connection-error
    error
    WhenNetwork connectivity issues (TCP connection failed, timeout, DNS failure)
    ThrowsError with code: ECONNECTION, ETIMEDOUT, EDNS, ESOCKET
    Required handlingCaller MUST catch connection errors. ECONNECTION: TCP connection failed or closed unexpectedly. ETIMEDOUT: Connection/greeting/socket timeout (defaults: 2min/30s/10min). EDNS: Hostname DNS resolution failed. ESOCKET: Low-level socket error from net/tls modules. These errors are TRANSIENT and RETRIABLE with exponential backoff.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[1]
  • sendMail · authentication-failure
    error
    WhenSMTP authentication fails (wrong credentials, locked account, unsupported auth)
    ThrowsError with code: EAUTH, ENOAUTH, EOAUTH2
    Required handlingCaller MUST catch authentication errors. EAUTH: Invalid username/password, account locked, unsupported auth method. ENOAUTH: Authentication required but not configured. EOAUTH2: OAuth2 token refresh failed or invalid credentials. DO NOT RETRY - indicates configuration issue. Check SMTP credentials and account status.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[2]
  • sendMail · tls-ssl-error
    error
    WhenTLS/SSL certificate validation fails or STARTTLS fails
    ThrowsError with code: ETLS, EREQUIRETLS
    Required handlingCaller MUST catch TLS errors. ETLS: Certificate validation failed, hostname mismatch, STARTTLS failed. EREQUIRETLS: RFC 8689 REQUIRETLS extension unsupported by server. DO NOT RETRY - indicates certificate or TLS configuration issue. Verify SSL certificate validity and STARTTLS support. v9.0.0+ EXPANDED SURFACE (2026-06-14): TLS validation is now strict by default for HTTPS requests during: (1) attachment fetching when href/path is an HTTPS URL, (2) OAuth2 token endpoint requests, (3) HTTPS proxy CONNECT tunnels. Code paths that worked against self-signed or expired certs in v8 will now throw a TLS error during sendMail(). DO NOT relax with tls.rejectUnauthorized=false except for explicitly-trusted internal CAs.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[3][4]
  • sendMail · invalid-recipient
    error
    WhenRecipient email address is malformed or rejected
    ThrowsError with code: EENVELOPE
    Required handlingCaller MUST validate email addresses before sending. EENVELOPE: Invalid recipient format, missing from/to address, SMTP rejected. Validate against RFC 5321/5322 before calling sendMail(). Check info.rejected array for partial failures. SECURITY: Sanitize addresses to prevent CVE-2021-23400 (header injection).
    costmediumin prodimmediate exceptionusers seelost transactionvisibilitysilent
    Sources[5]
  • sendMail · message-content-error
    error
    WhenMessage content is invalid or attachments fail to load
    ThrowsError with code: EMESSAGE, EFILEACCESS, EURLACCESS, EFETCH, ESTREAM
    Required handlingCaller MUST validate message content and attachments. EMESSAGE: Invalid message structure, encoding issues. EFILEACCESS: Attachment file not found or unreadable (also raised when disableFileAccess is set and a file path is encountered, including v9.0.1+ enforcement of the option for raw message attachments). EURLACCESS: Cannot fetch URL attachment (also raised when disableUrlAccess blocks an http(s) attachment URL). EFETCH: HTTP error fetching remote content (since v9.0.0 also surfaces TLS validation failures on attachment HTTPS URLs by default — see tls-ssl-error for the certificate-validation surface). ESTREAM: Attachment stream failed. Verify attachment paths exist and are readable before sending. For user-supplied attachment URLs, set disableUrlAccess: true and provide attachments inline as Buffer/string to avoid network fetches.
    costlowin prodimmediate exceptionusers seelost transactionvisibilitysilent
    Sources[6][4]
  • sendMail · protocol-error
    error
    WhenSMTP protocol violation or configuration error
    ThrowsError with code: EPROTOCOL, ECONFIG, EMAXLIMIT, EPROXY
    Required handlingCaller MUST handle protocol errors. EPROTOCOL: SMTP protocol error from server. ECONFIG: Invalid transport configuration. EMAXLIMIT: Message size exceeds server limit. EPROXY: HTTP/HTTPS proxy CONNECT tunnel failed (since v9.0.0 also includes TLS validation failures on the proxy endpoint by default). Check SMTP server logs and message size limits.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[7][8]
  • sendMail · transport-specific-error
    error
    WhenTransport implementation raises a transport-tagged error (added v8.0.11+)
    ThrowsError with code: ESES, ESENDMAIL
    Required handlingCaller MUST distinguish transport-tagged errors from generic SMTP errors when running multiple transports in the same process. Without the code tag, retry logic and alerting cannot route errors to the right runbook. ESES: AWS SES transport error (added v8.0.11). Underlying SES SDK error wrapped with the ESES code so callers can detect "this was the SES transport, not generic SMTP". The wrapped error preserves the SES HTTP status and SDK error name on err.responseCode and err.response. ESENDMAIL: Local sendmail binary error. Process spawn failed, sendmail exited non-zero, or local mail queue rejected the message. NOT retriable in-process — escalate to ops, do not loop. For ESES specifically: check err.responseCode for AWS HTTP status (429 = throttle/retriable; 4xx = config issue; 5xx = SES outage).
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[9][8]
  • verify · verification-failure
    error
    WhenSMTP connection or authentication fails during verification
    ThrowsError with code: ECONNECTION, EAUTH, ETLS, EDNS, ETIMEDOUT
    Required handlingCaller MUST catch verification errors. Call verify() during application initialization to catch config issues early. Same error codes as sendMail() connection/auth errors. Verification failure indicates configuration problem - fix before deployment.
    costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[10]
  • createTransport · configuration-error
    info
    WhenInvalid transport configuration
    ReturnsTransporter instance (errors deferred to sendMail/verify)
    Required handlingNo try-catch needed for createTransport(). Configuration errors are deferred and surface when sendMail() or verify() is called. Best practice: call verify() after createTransport() to validate configuration early. Use environment variables for credentials, never hardcode.
    costlowin prodsilent failureusers seedegraded performancevisibilitysilent
    Sources[11]
  • createTestAccount · create-test-account-network-error
    error
    WhenEthereal API (api.nodemailer.com) is unreachable or connection fails
    ThrowsError (no code) — raw ECONNREFUSED, ETIMEDOUT, ENOTFOUND from HTTP layer
    Required handlingCaller MUST catch network errors from createTestAccount(). Unlike sendMail(), this error has no structured code field — it is the raw network error from Node.js HTTP (ECONNREFUSED, ETIMEDOUT, ENOTFOUND). DO NOT use createTestAccount() in production app startup — if Ethereal API is down, it will crash your app initialization. BEST PRACTICE: Call createTestAccount() only in test setup scripts with full try/catch. Cache the result (it is already module-scoped by nodemailer).
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[12]
  • createTestAccount · create-test-account-api-error
    warning
    WhenEthereal API returns non-success status or error field in response
    ThrowsError with message from data.error or 'Request failed'
    Required handlingCaller MUST catch API-level errors. Ethereal API returns { status: 'error', error: 'message' } for failures including rate limits, server errors, and account creation failures. This error has no .code property — check err.message for details. RETRY: These errors are generally transient — retry after delay. FALLBACK: Use static test credentials (saved from a previous successful call) or configure a real test SMTP server (Mailhog, Mailtrap) instead of Ethereal.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[13]
  • createTestAccount · create-test-account-parse-error
    warning
    WhenEthereal API returns invalid JSON (service outage, CDN error page)
    ThrowsSyntaxError (JSON parse failure)
    Required handlingCaller MUST catch SyntaxError from createTestAccount(). During Ethereal API outages, the response may be an HTML error page (Cloudflare 5xx, maintenance page) instead of JSON. JSON.parse() throws SyntaxError. Check err instanceof SyntaxError to distinguish from network/API errors. FALLBACK: Use hardcoded test SMTP credentials or local mail catcher.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[14]

Sources

Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.

Official documentation
  • [1]
    nodemailer.com/errors
    Errors
  • [2]
    nodemailer.com/errors
    Errors
  • [3]
    nodemailer.com/smtp
    Smtp
  • [5]
    nodemailer.com/errors
    Errors
  • [6]
    nodemailer.com/message/attachments
    Attachments
  • [7]
    nodemailer.com/errors
    Errors
  • [10]
    nodemailer.com/usage
    Usage
  • [11]
    nodemailer.com/smtp
    Smtp
Source code
Changelog & releases

Research notes

Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.

nodemailer - Error Handling Sources

Package: nodemailer Version: >=7.0.11 Last Updated: 2026-02-26 Research Scope: Documentation, CVE analysis, real-world usage patterns


Official Documentation

Error Reference

  • URL: https://nodemailer.com/errors/
  • Content: Complete error code reference with 25+ error types
  • Key Errors:
    • ECONNECTION - TCP connection failed or closed unexpectedly
    • ETIMEDOUT - Connection/greeting/socket timeout (defaults: 2min/30s/10min)
    • EDNS - Hostname DNS resolution failed
    • ESOCKET - Low-level socket error from net/tls modules
    • ETLS - Certificate validation failed, hostname mismatch, STARTTLS failed
    • EREQUIRETLS - RFC 8689 REQUIRETLS extension unsupported
    • EAUTH - Invalid credentials, locked account, unsupported auth method
    • ENOAUTH - Authentication required but not configured
    • EOAUTH2 - OAuth2 token refresh failed or invalid credentials
    • EENVELOPE - Invalid recipient format, missing from/to, SMTP rejected
    • EMESSAGE - Invalid message structure or encoding issues
    • EFILEACCESS - Attachment file not found or unreadable
    • EURLACCESS - Cannot fetch URL attachment
    • EFETCH - HTTP error fetching remote content
    • ESTREAM - Attachment stream failed
    • EPROTOCOL - SMTP protocol error from server
    • ECONFIG - Invalid transport configuration
    • EMAXLIMIT - Message size exceeds server limit
    • EPROXY - SOCKS proxy connection failed
    • ESENDMAIL - Sendmail binary execution failed
    • ESES - AWS SES specific error

Usage Guide

  • URL: https://nodemailer.com/usage/
  • Content: sendMail(), verify(), error handling patterns
  • Key Behaviors:
    • sendMail() returns Promise with SentMessageInfo
    • info.accepted - Array of successfully accepted recipients
    • info.rejected - Array of rejected recipients
    • info.rejectedErrors - Detailed errors per rejected recipient
    • Always await sendMail() in async functions
    • Check info.rejected for partial failures

SMTP Transport

  • URL: https://nodemailer.com/smtp/
  • Content: SMTP configuration, authentication methods, TLS/SSL
  • Key Behaviors:
    • Authentication methods: Login, OAuth2, Custom, CRAM-MD5
    • Connection pooling: pool: true (default 5 connections)
    • TLS options: secure (port 465), requireTLS, rejectUnauthorized
    • Timeout defaults: connectionTimeout: 2min, greetingTimeout: 30s, socketTimeout: 10min

Pooled SMTP

  • URL: https://nodemailer.com/smtp/pooled/
  • Content: High-volume email sending with connection pooling
  • Key Behaviors:
    • Reuse transporter instance for multiple emails
    • Pool size configurable via pool and maxConnections
    • Automatic connection management
    • Better performance than creating new transporter each time

Attachments

  • URL: https://nodemailer.com/message/attachments/
  • Content: File attachments, streaming, embedded images
  • Key Behaviors:
    • File attachments: filename, path, content
    • Stream attachments: streamSource
    • URL attachments: href
    • Embedded images: cid content ID
    • Encoding options: encoding (base64, etc.)
    • Error handling: Check file existence before sending

Message Configuration

  • URL: https://nodemailer.com/message/
  • Content: Email headers, HTML, text, addresses
  • Key Behaviors:
    • Address formats: "Name <email@example.com>" or { name, address }
    • Multiple recipients: Array of addresses
    • HTML vs plain text: Both can be provided
    • Custom headers: headers object

OAuth2 Authentication

  • URL: https://nodemailer.com/smtp/oauth2/
  • Content: Gmail, Office 365, custom OAuth2
  • Key Behaviors:
    • OAuth2 3-legged flow for user authorization
    • Token refresh handling
    • Error: EOAUTH2 when token refresh fails
    • Fallback to username/password if OAuth2 fails

Security Vulnerabilities (CVEs)

CVE-2020-7769 - Command Injection (CRITICAL)

  • CVSS: 9.8 (Critical)
  • Affected Versions: < 6.4.16
  • Fixed In: 6.4.16
  • Published: 2020-11-12
  • NVD: https://nvd.nist.gov/vuln/detail/CVE-2020-7769
  • Snyk: https://security.snyk.io/vuln/SNYK-JS-NODEMAILER-1038834
  • Description: Command injection vulnerability in sendmail transport. Crafted recipient email addresses can inject arbitrary command flags when sending mails.
  • Weakness: CWE-88 (Improper Neutralization of Argument Delimiters in a Command)
  • Attack Vector: Network (AV:N), Low Complexity (AC:L), No Privileges Required (PR:N), No User Interaction (UI:N)
  • Impact: High Confidentiality, High Integrity, High Availability
  • Workaround:
    • Validate and sanitize all recipient email addresses
    • Use SMTP transport instead of sendmail transport
    • Upgrade to 6.4.16 or later
  • Contract Implication: MUST validate email addresses before passing to sendMail()

CVE-2021-23400 - HTTP Header Injection (HIGH)

CVE-2025-14874 - Denial of Service (HIGH)

  • CVSS: 7.5 (High)
  • Affected Versions: < 7.0.11
  • Fixed In: 7.0.11
  • Published: 2025-01-18
  • NVD: https://nvd.nist.gov/vuln/detail/CVE-2025-14874
  • Description: DoS vulnerability via infinite recursion in email address parser. Crafted email address header can trigger infinite recursion causing stack overflow and application crash.
  • Weakness: CWE-703 (Improper Check or Handling of Exceptional Conditions)
  • Attack Vector: Network (AV:N), Low Complexity (AC:L), No Privileges Required (PR:N), No User Interaction (UI:N)
  • Impact: No Confidentiality impact, No Integrity impact, High Availability impact (DoS)
  • Patch Commit: https://github.com/nodemailer/nodemailer/commit/b61b9c0cfd682b6f647754ca338373b68336a150
  • Affected Products:
    • Nodemailer for Node.js
    • Red Hat Advanced Cluster Management for Kubernetes 2.0
    • Red Hat Ceph Storage 8.0
    • Red Hat Developer Hub
  • Workaround:
    • Validate email addresses to reject deeply nested group constructs
    • Limit recursion depth manually if parsing addresses
    • Upgrade to 7.0.11 or later (limits recursive parsing to max depth 50)
  • Contract Implication: Upgrade to 7.0.11+ immediately to prevent DoS

CVE-2025-13033 - Email Parsing Misrouting (MEDIUM)

  • CVSS: TBD (Medium estimated)
  • Affected Versions: <= 7.0.6
  • Fixed In: 7.0.7
  • Published: 2025-01-20
  • Description: Email parsing library incorrectly handles quoted local-parts containing '@' symbols, leading to misrouting of email recipients.
  • Weakness: Interpretation Conflict / Email Parsing Error
  • Attack Vector: Network
  • Impact: Email misrouting, potential information disclosure to unintended recipients
  • Workaround:
    • Validate email addresses against RFC 5321/5322
    • Avoid using quoted local-parts with '@' symbols
    • Upgrade to 7.0.7 or later
  • Contract Implication: Upgrade to 7.0.11+ for complete fix

Minimum Safe Version

CRITICAL: All users MUST upgrade to nodemailer 7.0.11 or later

Upgrade Path:

  • From 6.4.x or earlier → Critical upgrade (CVE-2020-7769, CVE-2021-23400)
  • From 6.5.x to 6.6.0 → High priority (CVE-2021-23400)
  • From 6.6.1 to 7.0.6 → High priority (CVE-2025-14874, CVE-2025-13033)
  • From 7.0.7 to 7.0.10 → Important (CVE-2025-14874)
  • 7.0.11 or later → No known CVEs

Real-World Usage Patterns

GitHub Issues Analysis

Issue #1174 - Missing await in Lambda

  • URL: https://github.com/nodemailer/nodemailer/issues/1174
  • Pattern: Missing await in serverless environments
  • Frequency: Very Common (30-40% of reported issues)
  • Symptom: Emails not sending in AWS Lambda/Cloud Functions
  • Root Cause: Function terminates before sendMail() promise resolves
  • Example:
    // ❌ WRONG
    exports.handler = async (event) => {
      transporter.sendMail(mailOptions); // Missing await!
      return { statusCode: 200 };
    };
    
    // ✅ CORRECT
    exports.handler = async (event) => {
      await transporter.sendMail(mailOptions);
      return { statusCode: 200 };
    };
    
  • Contract Implication: ERROR severity - MUST await sendMail() in async functions

Issue #1002 - Serverless Silent Failures

  • URL: https://github.com/nodemailer/nodemailer/issues/1002
  • Pattern: No error logging in serverless
  • Root Cause: Promise rejection after function termination
  • Fix: Always await and use try-catch
  • Contract Implication: Combine await requirement with error handling requirement

Issue #414 - Unhandled Promise Rejection

  • URL: https://github.com/nodemailer/nodemailer/issues/414
  • Pattern: No try-catch around sendMail()
  • Frequency: Very Common
  • Symptom: Application crashes on email errors
  • Example:
    // ❌ WRONG
    await transporter.sendMail(mailOptions);
    
    // ✅ CORRECT
    try {
      const info = await transporter.sendMail(mailOptions);
      if (info.rejected.length > 0) {
        console.error('Some recipients rejected:', info.rejected);
      }
    } catch (error) {
      console.error('Failed to send email:', error.code, error.message);
    }
    
  • Contract Implication: ERROR severity - MUST wrap sendMail() in try-catch

Issue #1124 - Authentication Failures

  • URL: https://github.com/nodemailer/nodemailer/issues/1124
  • Pattern: EAUTH errors not handled separately
  • Symptom: Infinite retry loops on authentication failures
  • Fix: Check error.code and don't retry EAUTH
  • Contract Implication: Document non-retriable errors (EAUTH, ENOAUTH, ETLS)

Issue #1289 - Header Injection (CVE-2021-23400)

  • URL: https://github.com/nodemailer/nodemailer/issues/1289
  • Pattern: No input validation on email addresses
  • Severity: High (Security vulnerability)
  • Fix: Sanitize: email.replace(/[\r\n]/g, '')
  • Contract Implication: WARNING severity - MUST sanitize email addresses

Issue #206 - No verify() before production

  • URL: https://github.com/nodemailer/nodemailer/issues/206
  • Pattern: Configuration errors discovered in production
  • Fix: Call verify() during application startup
  • Example:
    const transporter = nodemailer.createTransport(config);
    
    // Verify during startup
    try {
      await transporter.verify();
      console.log('SMTP server is ready');
    } catch (error) {
      console.error('SMTP configuration error:', error);
      process.exit(1);
    }
    
  • Contract Implication: INFO severity - SHOULD call verify() during initialization

Issue #1179 - Runtime Configuration Failures

Issue #1340 - No Retry Logic

  • URL: https://github.com/nodemailer/nodemailer/issues/1340
  • Pattern: Transient errors treated as permanent failures
  • Fix: Implement exponential backoff for ECONNECTION, ETIMEDOUT
  • Example:
    async function sendWithRetry(mailOptions, maxRetries = 3) {
      for (let attempt = 1; attempt <= maxRetries; attempt++) {
        try {
          return await transporter.sendMail(mailOptions);
        } catch (error) {
          const retriable = ['ECONNECTION', 'ETIMEDOUT', 'EDNS', 'ESOCKET'];
          if (!retriable.includes(error.code) || attempt === maxRetries) {
            throw error;
          }
          await sleep(Math.pow(2, attempt) * 1000);
        }
      }
    }
    
  • Contract Implication: INFO severity - SHOULD implement retry for transient errors

Issue #405 - Permanent Failures for Temporary Issues

Issue #670 - Pool Exhaustion

  • URL: https://github.com/nodemailer/nodemailer/issues/670
  • Pattern: Creating new transporter for each email
  • Symptom: Connection pool exhaustion, poor performance
  • Fix: Reuse transporter instance
  • Contract Implication: INFO severity - SHOULD reuse transporter

Issue #303 - Attachment File Not Found

Issue #703 - Partial Failures Ignored

  • URL: https://github.com/nodemailer/nodemailer/issues/703
  • Pattern: Not checking info.rejected array
  • Symptom: Silent failures for some recipients
  • Fix: Always check info.rejected and info.rejectedErrors
  • Contract Implication: WARNING severity - MUST check info.rejected

Common Production Mistakes (Summary)

1. Missing await in serverless (CRITICAL)

  • Frequency: Very Common (30-40% of issues)
  • Consequence: Silent email failures
  • Fix: Always await sendMail()

2. No error handling on sendMail() (HIGH)

  • Frequency: Very Common
  • Consequence: Unhandled promise rejections crash app
  • Fix: Wrap in try-catch

3. No input validation (HIGH - Security)

  • Frequency: Common
  • Consequence: Enables CVE-2021-23400 header injection
  • Fix: Sanitize addresses: email.replace(/[\r\n]/g, '')

4. Creating new transporter each time (MEDIUM)

  • Frequency: Common
  • Consequence: Poor performance, connection overhead
  • Fix: Create once, reuse

5. No retry logic for transient errors (MEDIUM)

  • Frequency: Common
  • Consequence: Permanent failures for temporary issues
  • Fix: Retry ECONNECTION, ETIMEDOUT, EDNS, ESOCKET

6. Ignoring rejected recipients (MEDIUM)

  • Frequency: Common
  • Consequence: Silent partial failures
  • Fix: Check info.rejected array

7. Not calling verify() before production (LOW)

  • Frequency: Occasional
  • Consequence: Config errors in production
  • Fix: Call verify() during startup

Community Resources

Tutorials

Retry Strategies


Error Handling Decision Tree

sendMail() throws error
│
├─ error.code === 'ECONNECTION' → RETRY (network issue)
├─ error.code === 'ETIMEDOUT' → RETRY (timeout)
├─ error.code === 'EDNS' → RETRY (DNS temporary failure)
├─ error.code === 'ESOCKET' → RETRY (socket error)
│
├─ error.code === 'EAUTH' → FAIL FAST (wrong credentials)
├─ error.code === 'ENOAUTH' → FAIL FAST (missing auth config)
├─ error.code === 'EOAUTH2' → FAIL FAST (OAuth2 token invalid)
│
├─ error.code === 'ETLS' → FAIL FAST (certificate issue)
├─ error.code === 'EREQUIRETLS' → FAIL FAST (TLS not supported)
│
├─ error.code === 'EENVELOPE' → FAIL FAST (invalid address)
├─ error.code === 'EMESSAGE' → FAIL FAST (invalid message)
├─ error.code === 'EFILEACCESS' → FAIL FAST (attachment missing)
│
└─ Unknown error → LOG AND FAIL

Version History

  • 7.0.11 (2025-01-18) - Fixed CVE-2025-14874 (DoS)
  • 7.0.7 (2025-01-20) - Fixed CVE-2025-13033 (misrouting)
  • 6.6.1 (2021-07-15) - Fixed CVE-2021-23400 (header injection)
  • 6.4.16 (2020-11-12) - Fixed CVE-2020-7769 (command injection)

Research Completeness:

  • ✅ 13 documentation sources
  • ✅ 4 CVEs analyzed
  • ✅ 12 GitHub issues reviewed
  • ✅ 25+ error codes documented
  • ✅ 7 common production bugs identified
  • ✅ Retry strategies documented
  • ✅ Security best practices included

Last Updated: 2026-02-26

Need a different package?
Request a profile