# Nodemailer ECONNREFUSED 127.0.0.1:587: missing SMTP host

Nodemailer ECONNREFUSED on 127.0.0.1 or ::1 means the SMTP host was empty, so it tried your own machine. We reproduced it; the error message can even be blank.

Author: Formgong
Published: 2026-10-16
Language: en
Canonical: https://formgong.com/en/blog/nodemailer-econnrefused/

ECONNREFUSED to 127.0.0.1 or ::1 means Nodemailer tried a mail server on the same machine and nothing was listening. Usually the host option is undefined because SMTP_HOST is not set, so Nodemailer falls back to localhost. Set the variable on the host and restart. ECONNREFUSED to another IP means the host is wrong or the port is closed there.

## What we saw

*Figure: A contact form shows an error after Send. The terminal shows an AggregateError with an empty message; inside it, connect ECONNREFUSED ::1:587 and 127.0.0.1:587, because SMTP_HOST was undefined.*

On 16.10.2026 we created a transport with Node.js 22.23 and nodemailer 10.1.1 and `host: process.env.SMTP_HOST` while the variable was unset. Nodemailer did not complain about the missing host. It connected to `localhost`, found nothing on port 587, and failed in 66 ms.

The error was an `AggregateError` with `code: "ESOCKET"` and an empty `message`. The two real errors sat inside `err.errors`: `connect ECONNREFUSED ::1:587` and `connect ECONNREFUSED 127.0.0.1:587`, one per address localhost resolves to. Code that logs only `err.message` prints a blank line here, which makes the problem look stranger than it is. Log the whole error object.

## Reading the address in the error

ECONNREFUSED in Nodemailer
Address in the errorLikely cause

`127.0.0.1:587` or `::1:587`The host is empty or `localhost`. An unset `SMTP_HOST`, a typo in the variable name, or a config copied from a tutorial that ran its own mail server.
`127.0.0.1:1025` and similarA local catcher such as MailHog or Mailpit in your dev config, not running, or the dev config shipped to production.
Some other IPThe host resolved, but nothing accepts that port there. On our test the typo `smtp.gmial.com` resolved to a real IP and refused port 587.

Inside Docker, `localhost` is the container itself, not your computer, so a mail catcher running on the host is “refused” from inside the container. Use the service name from your compose file, or `host.docker.internal` on Docker Desktop.

## Fail early when the host is missing

Check the variables at startup so a missing host stops the server with its name in the log, then let `verify()` connect once before real traffic arrives.

```javascript
// Fail at startup with a clear message instead of failing on the first visitor's message.
for (const name of ["SMTP_HOST", "SMTP_PORT", "SMTP_USER", "SMTP_PASS"]) {
  if (!process.env[name]) throw new Error(`${name} is not set`);
}

const transporter = nodemailer.createTransport({
  host: process.env.SMTP_HOST,
  port: Number(process.env.SMTP_PORT),
  secure: Number(process.env.SMTP_PORT) === 465, // true only for 465
  auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS },
});

await transporter.verify(); // connects and logs in, sends nothing
```

## Do you need an SMTP host for a contact form?

If the SMTP login exists only so a contact form can email you, you can drop it: a form that posts to [Formgong](/en/) at `https://formgong.com/submit` has no SMTP host, port or password in your code, and Formgong sends the notification itself. See the [HTML guide](/en/docs/html/).

## Frequently asked questions

### Why does Nodemailer connect to 127.0.0.1 when I set a host?

The value your code passed was empty, usually an unset environment variable, so Nodemailer used localhost. Print typeof process.env.SMTP_HOST on the server to confirm.

### Why is the Nodemailer error message empty?

On our test the failure came back as an AggregateError with an empty message; the details were in err.errors. Log the whole error object, not only err.message.

### What does ECONNREFUSED mean?

The machine at that address answered, but no program accepts connections on that port. For a remote host it can also mean the port is closed or blocked.

## Sources and documentation

- [Nodemailer: SMTP transport (host defaults)](https://nodemailer.com/smtp/)
- [Node.js: Common system errors (ECONNREFUSED)](https://nodejs.org/api/errors.html#common-system-errors)
- [MDN: AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError)
- [HTML contact form](https://formgong.com/en/docs/html/)

[Get a form key](https://formgong.com/en/#top)
