Minimal Midway.js 3 (Koa) example that sends test mail through Mailexam SMTP via Nodemailer.
Based on the Mailexam Midway.js guide.
- A Mailexam account and a project with SMTP credentials.
- Node.js 18+ and npm.
From your Mailexam welcome email or dashboard:
| Variable | Description |
|---|---|
MAILEXAM_LOGIN |
SMTP login (for example, xxxxx) |
MAILEXAM_PASSWORD |
SMTP password (paired with the login) |
| Host | {MAILEXAM_LOGIN}.mailexam.io (built automatically in code) |
- Install dependencies:
npm install- Copy the example environment file and fill in your credentials:
cp .env.example .env- Edit
.env:
MAILEXAM_LOGIN=YOUR_LOGIN
MAILEXAM_PASSWORD=YOUR_PASSWORD
MAILEXAM_PORT=587
MAIL_FROM=noreply@example.test- Build and run the server:
npm run build
npm startThe server listens on http://127.0.0.1:7001 by default.
- Send a test message:
curl -X POST http://127.0.0.1:7001/mail/test \
-H 'Content-Type: application/json' \
-d '{"to":"user@example.test","subject":"Test","text":"Hello"}'The message appears in the Mailexam dashboard → your project → inbox.
| Variable | Required | Default | Description |
|---|---|---|---|
MAILEXAM_LOGIN |
yes | — | SMTP login; also used to build the host name |
MAILEXAM_PASSWORD |
yes | — | SMTP password |
MAILEXAM_PORT |
no | 587 |
SMTP port (587, 2525, or 465) |
MAIL_FROM |
no | noreply@example.test |
Sender address |
HTTP_HOST |
no | 127.0.0.1 |
HTTP bind address |
HTTP_PORT |
no | 7001 |
HTTP listen port |
For port 587 the transport uses STARTTLS (secure: false). For port 465 it uses SMTPS (secure: true).
.
├── package.json
├── tsconfig.json
├── bootstrap.js # loads .env, starts Midway
├── src/
│ ├── configuration.ts
│ ├── config/config.default.ts
│ ├── service/mail.service.ts
│ └── controller/mail.controller.ts
├── .env.example
├── Dockerfile # for local debugging only
└── docker-compose.yml
Docker is provided for local debugging. For day-to-day development, run the app on the host with npm run build && npm start (see above).
cp .env.example .env
# edit .env with your credentials
docker compose up --buildThen call the same endpoint on the mapped port:
curl -X POST http://127.0.0.1:7001/mail/test \
-H 'Content-Type: application/json' \
-d '{"to":"user@example.test","subject":"Test","text":"Hello"}'Inside the container the server binds to 0.0.0.0:7001.
Set these secrets in your CI environment:
variables:
MAILEXAM_LOGIN: $MAILEXAM_LOGIN
MAILEXAM_PASSWORD: $MAILEXAM_PASSWORD
MAILEXAM_PORT: "587"
MAIL_FROM: "noreply@example.test"After sending a message in a test, verify delivery via the Mailexam API.
Connection timeout / authentication failed
- Host must be
{login}.mailexam.io, where{login}matchesMAILEXAM_LOGIN. - Login and password must come from the same Mailexam project.
Port 587 and TLS
- For 587:
secure: false(STARTTLS). For 465:secure: true.
Variables undefined
- Add a
.envfile in the project root or export variables in your shell/CI. bootstrap.jsloads.envviadotenvbefore the app starts.
Message not in the dashboard
- Open the inbox of the same Mailexam project.
- Check server logs for SMTP errors on
sendMail.
- Mailexam Midway.js guide (wiki)
- NestJS reference implementation — another Node.js framework with Nodemailer
- Midway.js documentation
- Nodemailer documentation
- Mailexam API documentation