Skip to main content

Sending Emails with Nodemailer & IONOS SMTP: Correct Ports & TLS Settings

 Few debugging sessions are as frustrating as diagnosing SMTP connection timeouts. You have a functioning Node.js application, valid credentials, and a standard library like Nodemailer, yet the email refuses to send. When integrating IONOS (formerly 1&1) with Node.js, developers frequently encounter generic errors like ETIMEDOUT, ESOCKET, or authentication failures.

The issue rarely lies in the credentials themselves. instead, it stems from a mismatch between the SMTP port and the encryption protocol negotiation (Implicit TLS vs. STARTTLS).

This guide dissects the underlying TCP/IP handshake mechanisms causing these failures and provides a copy-paste, production-ready configuration for sending emails securely via IONOS.

The Root Cause: Implicit TLS vs. STARTTLS

To fix the configuration, you must understand how the connection is established. IONOS supports two primary modes of operation, and Nodemailer requires specific flags for each. Mixing them is the primary cause of hanging sockets.

1. Port 465 (Implicit TLS)

When connecting to port 465, the client (Nodemailer) expects the server to initiate a TLS handshake immediately upon connection establishment. If your code connects to port 465 but sets secure: false, the server waits for a handshake, the client waits for a cleartext greeting, and the connection eventually times out.

2. Port 587 (Explicit TLS / STARTTLS)

When connecting to port 587, the connection starts in cleartext. The client issues an EHLO command, followed by STARTTLS. Only then is the connection upgraded to an encrypted tunnel. If you use port 587 but set secure: true, Nodemailer attempts to handshake immediately over cleartext, resulting in garbage data and a severed connection.

The Solution: Production-Ready Configuration

Below is a modern, modular implementation using ES Modules (ESM) and async/await. It handles environment variables securely and includes the specific logic required for IONOS.

Prerequisites

Ensure you have the necessary packages:

npm install nodemailer dotenv

The Implementation

Create a file named mailer.js. This solution prioritizes Port 587 (STARTTLS) as it is the modern standard, but includes comments for Port 465 if your firewall restricts 587.

import nodemailer from 'nodemailer';
import dotenv from 'dotenv';

// Load environment variables
dotenv.config();

/**
 * Creates a configured transporter for IONOS SMTP.
 * 
 * CRITICAL CONFIGURATION NOTES:
 * 1. Host: smtp.ionos.com (or smtp.ionos.de for Germany)
 * 2. Port 587: Requires secure: false (Uses STARTTLS)
 * 3. Port 465: Requires secure: true (Uses Implicit TLS)
 */
const createTransporter = () => {
  return nodemailer.createTransport({
    host: 'smtp.ionos.com',
    port: 587,
    secure: false, // true for 465, false for other ports
    auth: {
      user: process.env.SMTP_USER,
      pass: process.env.SMTP_PASS,
    },
    // Optional: Useful for debugging connection issues
    logger: true,
    debug: true, 
  });
};

/**
 * Sends an email using the configured transporter.
 * @param {Object} emailData - The email details
 */
export const sendEmail = async ({ to, subject, html }) => {
  const transporter = createTransporter();

  try {
    // Verify connection configuration before sending
    await transporter.verify();
    console.log('✅ SMTP Connection established successfully.');

    const info = await transporter.sendMail({
      from: `"Support Team" <${process.env.SMTP_USER}>`, // MUST match auth user
      to,
      subject,
      html,
    });

    console.log(`🚀 Email sent: ${info.messageId}`);
    return info;
  } catch (error) {
    console.error('❌ Email failed to send:', error.message);
    
    // Detailed error handling for common SMTP issues
    if (error.code === 'EAUTH') {
      console.error('Check your username and password.');
    } else if (error.code === 'ESOCKET') {
      console.error('Connection timed out. Check firewall and port settings.');
    }
    
    throw error;
  }
};

// Example Usage (Self-executing function for testing)
// In a real app, you would import and call sendEmail from your controller
if (process.argv[1] === import.meta.filename) {
  (async () => {
    try {
      await sendEmail({
        to: 'recipient@example.com',
        subject: 'IONOS SMTP Test',
        html: '<p>This is a secure test email via Node.js</p>',
      });
    } catch (err) {
      process.exit(1);
    }
  })();
}

Deep Dive: Why This Configuration Works

The secure Boolean

In Nodemailer, the secure option is the most misunderstood setting.

  • It does not determine if the email is encrypted (both methods result in encryption).
  • It determines when encryption happens.
  • Correction: port: 587 must pair with secure: false. The library will automatically detect STARTTLS support and upgrade the connection.

The "From" Header Restriction

IONOS enforces strict Sender Policy Framework (SPF) rules. You cannot authenticate as admin@yourdomain.com and send an email from: 'marketing@otherdomain.com'. The from address in the sendMail object must match the authenticated user in the createTransport object. Failure to do this results in a 550 Sender address is not allowed error.

Troubleshooting Common Edge Cases

1. ETIMEDOUT on Cloud Hosting (AWS/GCP/Azure)

If this code works locally but times out in production (AWS EC2, Google Cloud, DigitalOcean), the cloud provider is likely blocking outbound traffic on standard SMTP ports to prevent spam.

  • Diagnosis: The request hangs indefinitely.
  • Fix: You must request your cloud provider to unblock port 587, or use a dedicated third-party relay (SendGrid, SES, Mailgun) as IONOS is not designed for high-volume programmatic sending from cloud IPs.

2. Self-Signed Certificate Errors

In development environments, you might encounter preventing connection establishment. This happens if a proxy or antivirus intercepts the SSL connection.

You can bypass this temporarily (do not use in production) by adding a TLS override:

tls: {
  rejectUnauthorized: false
}

3. DNS Lookup Failures (EDNS)

If you receive ENOTFOUND or EDNS errors regarding smtp.ionos.com, your server's DNS resolver may be failing. This often happens inside Docker containers. Ensure your container has access to public DNS (like 8.8.8.8) or switch to the region-specific host smtp.ionos.de if your account is based in Europe.

Conclusion

Sending email via IONOS with Node.js relies on strict adherence to the protocol associated with the port you choose. By pairing Port 587 with secure: false and ensuring your sender identity matches your credentials, you eliminate the majority of connection and authentication errors. Always use environment variables for credentials and verify the connection status before attempting to send the payload.