NodeMailServer
Reference

Background workers

Which work runs in worker threads, how to size the pool and what clients see when it is busy.

Node runs JavaScript on one main thread. If that thread is busy with a large message, every other SMTP session waits. The server moves the heavy work to worker threads (worker_threads), so the main thread only handles network traffic and waiting.

What runs in a worker

TaskUsed by
authenticateDKIM, SPF and DMARC checks on incoming mail.
dkimSignSigning outgoing mail.
pgpEncryptEncrypting incoming mail for storage.
parseDsnReading bounce reports.
composeMimeBuilding the message for the JSON send API.

DNS lookups, sockets and file writes are already asynchronous, so they stay on the main thread.

Settings

VariableDefaultDescription
MAIL_WORKERSCPU cores minus 1, at most 4Number of worker threads. 0 runs everything on the main thread.
MAIL_WORKER_CONCURRENCY4Tasks one worker runs at the same time.
MAIL_WORKER_MAX_QUEUE1000Tasks allowed to wait for a free worker.
MAIL_WORKER_TIMEOUT_MS120000Longest a single task may run.

When the pool is busy

When MAIL_WORKER_MAX_QUEUE tasks are already waiting, new mail is not accepted for processing:

  • On port 25 and 587, the client gets 451 4.3.2 (the SERVER_BUSY reply in smtp-messages.json) and tries again later.
  • The JSON API answers 503.

If a worker stops, or a task runs longer than MAIL_WORKER_TIMEOUT_MS, that worker is replaced and its tasks fail. If the pool cannot start at all, the work runs on the main thread and the server logs it, so mail still flows.

Components involved

ComponentFilePurpose
WorkerPoolserver/src/lib/workers/WorkerPool.tsStarts, feeds and replaces the threads.
mail.worker.tsserver/src/lib/workers/mail.worker.tsThe code that runs inside a thread.
mailTasksserver/src/lib/workers/mailTasks.tsThe tasks themselves.
mailWorkersserver/src/lib/workers/index.tsThe functions the rest of the server calls.

On this page