Viesti Sign in

Send email from Node.js with Nodemailer

Nodemailer sends email from Node.js over SMTP. This guide sends a transactional email through Viesti over STARTTLS on port 587, with the API key read from the environment.

Before you start

  1. Sign in and verify the domain you send from. Viesti accepts a message only when its From address is on a domain verified in your workspace and the envelope sender (MAIL FROM), which most libraries take from the From address, is on the same domain. DNS setup lists the records.
  2. Create an API key on the Credentials page of the dashboard. It is shown once. The key is the SMTP password; the username is apikey.
Setting Value
Host smtp.viesti.email
Port 587 with STARTTLS, or 465 with TLS from the first byte
Username apikey
Password Your API key: mr_ followed by 64 hex characters
Authentication PLAIN, offered only once the connection is encrypted

Install Nodemailer

npm install nodemailer

Tested with Nodemailer 10.0.10 on Node.js 24.

Set the environment

export VIESTI_API_KEY="mr_your_api_key"
export MAIL_FROM="Acme <[email protected]>"

MAIL_FROM may carry a display name. Its domain must be verified in your workspace.

Send an email

Save this as send.mjs; it uses ES modules and top-level await.

import nodemailer from "nodemailer";

const transporter = nodemailer.createTransport({
  host: "smtp.viesti.email",
  port: 587,
  secure: false, // 587 starts in plain text, then upgrades with STARTTLS
  requireTLS: true, // fail instead of continuing without TLS
  auth: {
    user: "apikey",
    pass: process.env.VIESTI_API_KEY,
  },
});

const info = await transporter.sendMail({
  from: process.env.MAIL_FROM,
  to: "[email protected]",
  subject: "Your receipt",
  text: "Thanks for your order.",
  html: "<p>Thanks for your order.</p>",
});

console.log("Accepted:", info.messageId, info.response);

secure: false does not mean unencrypted: Nodemailer connects, then upgrades the connection with STARTTLS, which Viesti always offers on 587. requireTLS: true makes it fail rather than go on without the upgrade. Create the transporter once and reuse it for every message.

Test it

node send.mjs

A successful run prints the Message-ID and Viesti's reply:

Accepted: <…@your-verified-domain.com> 250 2.0.0 OK: queued

Then open Activity in the dashboard to follow the message to delivered. To check the connection and key without sending anything, call await transporter.verify(): it connects, upgrades to TLS and authenticates.

Port 465

If your network blocks outbound 587, use 465, where TLS starts before the SMTP greeting, and set secure: true:

const transporter = nodemailer.createTransport({
  host: "smtp.viesti.email",
  port: 465,
  secure: true, // TLS from the first byte
  auth: {
    user: "apikey",
    pass: process.env.VIESTI_API_KEY,
  },
});

Common errors

Error Cause and fix
ESOCKET … SSL routines:tls_validate_record_header:wrong version number secure: true on port 587. Use secure: false with 587, or port 465 with secure: true.
ETIMEDOUT Greeting never received after 30 seconds secure: false on port 465: the server waits for a TLS handshake while Nodemailer waits for a greeting. Set secure: true for 465.
EAUTH Missing credentials for "PLAIN" VIESTI_API_KEY is not set in the process that runs Nodemailer.
EAUTH Invalid login: 535 5.7.8 Authentication failed The key is wrong or revoked. Create a new one on the Credentials page; the username stays apikey.
EMESSAGE Message failed: 550 5.0.0 sending not permitted MAIL_FROM is not on a domain verified in your workspace. See DNS setup.

Replies from Viesti

Whatever the library, its error includes the server's reply. These are the ones caused by your setup or account:

Reply Meaning
535 5.7.8 Authentication failed The API key is wrong, revoked or empty. After ten failed attempts from one client address within ten minutes, that address is refused for ten minutes with 454 Too many failed authentications; retry later.
525 5.7.13 Workspace suspended; contact support The key is valid, but the workspace is suspended or under review. Write to [email protected]; a new key does not help.
550 5.0.0 sending not permitted The From domain is not verified in this workspace, the envelope sender is on a different domain than the From header, or the workspace is not active.
550 5.0.0 recipient suppressed The recipient is on your suppression list after a bounce or complaint; see Bounces.
451 4.0.0 submission quota exceeded The free plan's 75 emails per UTC day or 2,000 per UTC month are used up; see Limits. It is temporary: retry after the reset or upgrade.
452 4.5.3 Maximum limit of 50 recipients reached One message can have at most 50 recipients. Split the send.
552 5.0.0 message too large The message, attachments included, is over 10 MB.
554 5.0.0 rejected by content audit Content screening found the message in violation of the Terms of Service. It is not relayed.

A 250 reply means Viesti accepted the message. Content screening runs before relay; mail it flags is held for review and shows as quarantined on the Activity page.

Next steps

  • DNS setup: DKIM, SPF, DMARC and return-path records for your domain.
  • SMTP reference: ports, TLS and authentication in detail.
  • HTTP API: send the same message as JSON over HTTPS.
  • Limits and Bounces: quotas, message size and suppressions.

Nodemailer options are from the Nodemailer SMTP transport documentation. Checked 26 September 2026.