Why FaceKom “emails don’t send” in dev when they actually do — they land in a Mailtrap Sandbox inbox whose credentials are baked into config/dev.json, i.e. someone else’s / a shared testing inbox you can’t see. General FaceKom dev-testing knowledge (surfaced on FKITDEV-9059 cofidis testing), sibling to sms-verification-code-dev-testing.

TL;DR

config/dev.json ships a Mailtrap Sandbox SMTP config. Mail is delivered — into the baked inbox, not yours. To see it in your inbox, override email.transport.SMTP.host + auth.{user,pass} in the bind-mounted local config and point host at sandbox.smtp.mailtrap.io (the legacy smtp.mailtrap.io won’t auth current Sandbox creds).

The trap

config/dev.jsonemail.transport.SMTP ships a Mailtrap Sandbox inbox baked in:

FieldBaked value
hostsmtp.mailtrap.io (legacy; current host is sandbox.smtp.mailtrap.io)
port2525
auth.user643414e4c00185

So on any fresh cofidis (or other) dev box, registration / verification emails are delivered — but into whatever Mailtrap inbox those baked creds belong to (the original dev’s, or a shared one), not the person testing. The misleading symptom is “emails don’t send to Mailtrap” when in reality they send fine, just to an inbox you can’t see.

Route email to your own inbox

Override email.transport.SMTP.host + auth.{user,pass} in the bind-mounted local config — on fk-dev that is vuer_docker/tailscale/config/vuer_oss-local.json:

{
  "email": {
    "transport": {
      "SMTP": {
        "host": "sandbox.smtp.mailtrap.io",
        "port": 2525,
        "auth": { "user": "<your-inbox-user>", "pass": "<your-inbox-pass>" }
      }
    }
  }
}

The config loader is getconfig: it deep-merges default → all → {NODE_ENV} → local (last wins), so local.json is the only override point. Under NODE_ENV=dev, config/docker.json is NEVER loaded — do not put the override there (full loader detail in FKITDEV-9059).

Sandbox creds only auth against sandbox.smtp.mailtrap.io

The baked host is the legacy smtp.mailtrap.io. Current Mailtrap Sandbox SMTP credentials authenticate only against sandbox.smtp.mailtrap.io — so you must set the host, not just the user/pass.

Distinguish the two Mailtrap products

Getting this wrong is the second time-sink — Sandbox and live “Email Sending” use different hosts and different credential shapes.

ProductHostCredentialsBehaviour
Sandbox (testing)sandbox.smtp.mailtrap.ioper-inbox user/pass (~14 hex chars)Catches all mail in a testing inbox; nothing reaches real recipients. This is what you want for dev.
Email Sending (live)live.smtp.mailtrap.iousername api + a 32-char API tokenActually delivers to real recipients, needs a verified domain. Wrong for testing.

A ~14-hex-char user ⇒ Sandbox. A literal api username + long token ⇒ live sending (don’t use it to test).

Verify before you reconfigure

Probe the creds/host with nodemailer.verify() + a test sendMail before editing the app config, so you don’t chase a wrong host/cred combo through app restarts.

Use an absolute require path for nodemailer from /tmp

An ESM import of nodemailer from a script in /tmp can’t resolve the app’s node_modules. Use CommonJS with an absolute path:

const nodemailer = require('/workspace/vuer_oss/node_modules/nodemailer')

fk-dev config gotchas (context)

These are covered in full on FKITDEV-9059 / fk-dev-nusz-deploy-and-8959-verification; recapped because they bite exactly when you edit the email config:

  • config/dev.json has db.syncOnStart: true → the box runs migrate/sync on every boot. Restarting vuer_oss to pick up the config change also migrates the DB.
  • vuer_oss-local.json is a single-file bind mount (Docker binds the inode). Rewrite it with cat > file (inode-preserving). sed -i, mv, or git checkout -- replace the inode and the container silently keeps seeing the old file.

For Agents

  • Symptom: “FaceKom dev emails don’t send / don’t reach Mailtrap.” Reality: they send to the baked Sandbox inbox (config/dev.jsonemail.transport.SMTP, host smtp.mailtrap.io, port 2525, user 643414e4c00185), not yours.
  • Fix: override email.transport.SMTP.host = sandbox.smtp.mailtrap.io + auth.{user,pass} = your inbox, in vuer_docker/tailscale/config/vuer_oss-local.json (the getconfig local layer). config/docker.json is never loaded under NODE_ENV=dev.
  • Products: Sandbox = sandbox.smtp.mailtrap.io + user/pass (~14 hex), catches mail; Email Sending = live.smtp.mailtrap.io + api/32-char-token, delivers for real (wrong for dev).
  • Verify: nodemailer.verify() + test sendMail, requiring nodemailer by absolute path /workspace/vuer_oss/node_modules/nodemailer.
  • Bind mount: rewrite vuer_oss-local.json with cat > (inode-preserving), then restart (note db.syncOnStart:true migrates on boot).
  • FKITDEV-9059 — cofidis devel-update work where this surfaced; full getconfig loader + bind-mount detail
  • sms-verification-code-dev-testing — sibling guide: get the SMS/email verification code when the delivery channel is fake in dev
  • dev-build-host — fk-dev VM (bind-mounted config lives here)
  • fk-dev-nusz-deploy-and-8959-verification — fk-dev deploy recipe + the db.syncOnStart / single-file-bind-mount gotchas
  • security-audit — lists the Mailtrap SMTP credentials among the hardcoded dev-config test-service creds
  • vuer_oss — owns server/e-mail/EmailService.js (Nodemailer + MJML) and the email.transport config