Fob
Browse the docs

Use the library

The npm package that installs the CLI is also a Node.js library. The CLI calls the same functions, so anything a command can do, your code can do.

npm install @finopsbricks/fob-email

It's an ES module and needs Node.js 22.13 or later.

A client per mailbox#

import { fobEmail } from '@finopsbricks/fob-email';

const mbox = fobEmail('billing');
try {
  const { data } = await mbox.emails.list({ folder: 'INBOX', unseenOnly: true, limit: 20 });
  for (const envelope of data.filter((e) => e.hasAttachment)) {
    const files = await mbox.emails.download(envelope.id, { folder: 'INBOX' });
    // files: [{ filename, contentType, size, content: Buffer }]
    await mbox.emails.move(envelope.id, 'Invoices/2026', { folder: 'INBOX' });
  }
} finally {
  await mbox.close();
}

The client connects on first use. Always call close(), as above, or your process keeps the connection open.

Credentials#

fobEmail() takes an account in one of two forms:

You passWhere the credentials come from
A name, such as 'billing', or nothingFOB_EMAIL_ACCOUNTS, then ~/.fob/fob-email/config.yml, in the same order as the CLI
An object: { imap: { host, port, user, pass, tls }, smtp: { host, port, user, pass, secure } }Only that object. Nothing is read from the environment or config file

In a worker, pass the object built from your own secret store. That keeps the library from depending on any file on the machine.

What's on the client#

NamespaceMethods
emailslist({ folder, unseenOnly, limit }), search({ folder, criteria, limit }), get(id, { folder }), download(id, { folder }), mark(id, seen, { folder }), move(id, to, { folder }), delete(id, { folder }), send(message)
threadslist({ folder, limit }), show(id, { folder })
draftslist(), create(message), edit(id, message), delete(id), send(id)
folderslist(), create(path), rename(path, to), delete(path)
syncrun({ folder, full, limit }), runAll({ full, limit }), read({ folder, unseen, limit, from, subject, since }), status({ folder }), clear({ folder })
  • list and search return { data, uidValidity, folder }, where data is the array of messages described in JSON shapes.
  • search takes an imapflow search object as criteria, for example { from: '[email protected]', since: new Date('2026-09-01') }.
  • A message for send and drafts is { to: [...], cc, bcc, subject, text, attachments: [{ path, filename }] }.
  • sync.read() is synchronous and throws if the folder was never synced.

The same caveats as the CLI apply: IDs belong to a folder, and delete is permanent.

Helpers#

  • filterEmails(envelopes, { from, to, subject, hasAttachment, seen }) filters an array of messages in memory, like emails filter.
  • listEmails({ account, ...opts }) and readEmail({ account, id, folder }) connect, do one thing and close.
  • getProfile(account) signs in and returns { address, provider, threadStrategy, folders }.