Practical guide

Nodemailer “Missing credentials for "PLAIN"”: your SMTP variables are empty

Nodemailer raises this error itself, without a word from the mail server: the auth object reached it with an empty user or password. Where the value usually gets lost, and a check that catches it at startup.

The short answer. Missing credentials for "PLAIN" means Nodemailer was told to log in but got an empty user or password, usually because process.env.SMTP_USER or SMTP_PASS is undefined. The variables are in a .env file that is not loaded, have different names, or exist on your computer but not on the host. Set them where the code runs and restart or redeploy.

Formgong

Nodemailer “Missing credentials for "PLAIN"”: the fix
Nodemailer “Missing credentials for "PLAIN"”: your SMTP variables are empty

Nodemailer, not the server, throws it

On 16.10.2026 we gave Node.js 22.23 and nodemailer 10.1.1 the auth object { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS } with both variables unset, and sent through smtp.gmail.com. It connected, saw that Gmail offers the PLAIN login method, and threw Error: Missing credentials for "PLAIN" with code: "EAUTH" and command: "API".

command: "API" is the tell: the problem is in what your code passed, not in anything the server said. The word in quotes is the login method the server offered. A server that offers only LOGIN, such as Office 365, gives the same error with "LOGIN".

Where the value gets lost

  • The .env file is never loaded. Plain Node does not read .env by itself. Start with node --env-file=.env server.js or load dotenv before the transport is created.
  • It is loaded too late. If the module that creates the transport is imported before dotenv.config() runs, it read the variables while they were still empty.
  • The names differ. SMTP_PASSWORD in the file, SMTP_PASS in the code.
  • It works locally but not on the host. .env is not in Git, so Vercel, Netlify or your server never got it. Add the variables in the host's settings and redeploy. Our Next.js guide shows this case on a Vercel-style build.
  • The code runs in the browser. Variables without a public prefix are empty in front-end code, and an SMTP password must never be there anyway.

Catch it at startup

Check the variables when the server starts, then call verify(). A missing value then stops the deploy with its name in the log, instead of failing quietly on the first real message.

JavaScript (Node.js)
// 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 SMTP credentials 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 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.

Frequently asked questions

What does Missing credentials for PLAIN mean in Nodemailer?

Nodemailer got an empty user or password in the auth option, so it could not log in with the PLAIN method the server offered. The SMTP server never saw a password.

Why does it work locally but not on Vercel?

Your .env file stays on your computer. Add SMTP_USER and SMTP_PASS in the host's environment variables and redeploy.

What is the difference between PLAIN and LOGIN in this error?

Nothing that matters for the fix. It is the login method the server offered; Gmail offers PLAIN, Office 365 offers LOGIN. Both errors mean the credentials are empty.

Sources and documentation

Official references for this guide: Nodemailer: SMTP transport (auth options), Node.js: --env-file, Vercel: Environment variables. HTML contact form, where data is stored.

Rate this guide

Your rating

We read every rating. A comment appears here only after we approve it.

← Back to the blog